## Automatically generated incremental diff
## From:   linux-2.2.18-pre20
## To:     linux-2.2.18-pre21
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.2.18-pre20/CREDITS linux/CREDITS
--- linux-2.2.18-pre20/CREDITS	Mon Dec  3 22:14:07 2001
+++ linux/CREDITS	Mon Dec  3 22:14:15 2001
@@ -763,6 +763,15 @@
 S: Sterling Heights, Michigan 48313
 S: USA
 
+N: William Greathouse
+E: wgreathouse@smva.com
+E: wgreathouse@myfavoritei.com
+D: Current Belkin USB Serial Adapter F5U103 hacker
+D: Kernel hacker, embedded systems
+S: 7802 Fitzwater Road   
+S: Brecksville, OH  44141-1334
+S: USA
+
 N: Tristan Greaves
 E: Tristan.Greaves@icl.com
 E: tmg296@ecs.soton.ac.uk
diff -urN linux-2.2.18-pre20/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.18-pre20/Documentation/Configure.help	Mon Dec  3 22:14:07 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:14:15 2001
@@ -13,8 +13,6 @@
 #     http://www.traduc.org/kernelfr
 #   - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at
 #     http://visar.csustan.edu/~carlos/
-#   - Italian, by Alessandro Rubini (rubini@linux.it), at
-#     ftp://ftp-pavia1.linux.it/pub/linux/Configure.help
 #   - Polish, by Cezar Cichocki (cezar@cs.net.pl), at
 #     http://www.cs.net.pl/~cezar/Kernel
 #   - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder
@@ -13518,7 +13516,7 @@
 #
 # LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
 # LocalWords:  unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz
-# LocalWords:  cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd
+# LocalWords:  cdrom diskless netboot nfs xzvf ATAPI MB ide pavia pl pd
 # LocalWords:  HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN
 # LocalWords:  ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt
 # LocalWords:  BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB
diff -urN linux-2.2.18-pre20/Documentation/s390/xpram.txt linux/Documentation/s390/xpram.txt
--- linux-2.2.18-pre20/Documentation/s390/xpram.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/xpram.txt	Mon Dec  3 22:14:15 2001
@@ -0,0 +1,133 @@
+XPRAM
+=====
+
+The S/390 architecture supports more RAM than can be accessed as main memory.
+The LINUX for S/390 main memory is limited to 2 GB. However, additional
+memory can be declared as expanded storage. The S/390 architecture allows
+applications to access up to 16 TB of expanded storage (although the current
+hardware can only be equipped with up to 32 GB memory). Memory in the
+expanded storage range can be copied in 4 KB blocks to, or from, the main
+memory.
+
+An interesting feature of expanded storage is that is persistent with respect 
+to IPLs (booting) but volatile with respect to IMLs (power off/on).
+
+The XPRAM device driver is a block device driver that supports LINUX for S/390
+allowing it to access the expanded storage. Thus XPRAM can be used as a basis 
+for fast swap devices and/or fast file systems.
+
+Features
+++++++++
+XPRAM automatically detects whether expanded storage is available on the
+system. The expanded storage can be subdivided into up to 32 partitions, the
+default being a single partition. The XPRAM device driver has major number 35.
+The partitions have minor numbers 0 through 31. The hard sector size of XPRAM
+is set to 4096 bytes.
+
+Limitations
++++++++++++
+If expanded storage is not available, XPRAM cannot be used. Its initialization
+fails gracefully with a log message reporting the lack of expanded storage.
+
+Configuration option
+++++++++++++++++++++
+
+CONFIG_XPRAM
+
+Module name
++++++++++++
+
+XPRAM can be used as module. Its moduel name is xpram.o.
+
+Kernel parameter syntax
++++++++++++++++++++++++
+The kernel parameter is optional. The default defines the whole expanded 
+storage to be one partition.
+
+xpram_parts=<number_of_partition>[,<partition_size>[,...]]
+
+where <number_of_partitions> defines how many partitions the expanded storage 
+is split into. The i-th <partition_size> defines the size of the i-th 
+partition. 
+
+The syntax for sizes is:
+
+[0x]<non-negative_integer>[k|K|m|M|g|G]
+
+If the 0x prefix is used the subsequent number is interpreted as a hexadecimal
+value, otherwise it is interpreted as a decimal value (default). The
+non-negative_integer value may be followed by a magnitude:
+
+- k or K for kilo (1024) is the default
+- m or M for Mega (1024*1024)
+- g or G for Giga (1024*1024*1024)
+
+The <non-negative_integer> value multiplied by its magnitude defines the
+partition's size in bytes. The default size is 0.
+
+Any partition defined with a non-zero size is allocated the amount of memory
+specified by its non-negative_integer parameter.
+
+You can automatically allocate the remaining memory between a set of partitions
+by specifying zero for the size of each partition in the set. The following 
+formula is used to calculate the size for each of these partitions:
+
+                (available exp. storage - sum of all non-zero sizes specified)
+computed size = --------------------------------------------------------------
+                number of partitions with zero sizes
+
+This formula is only a good approximation of the actual size allocated to each
+partition. Because of the requirement to assign blocks in multiples of 4K, 
+partitions can be larger or smaller than the estimate produced by the 
+calculation. In addition, there might be an amount of memory left as a "guard 
+space" between two partitions.
+
+Example
+-------
+
+xpram_parts=4,0x800M,0,0,0x1000M
+
+This allocates the extended storage into four partitions. Partition 1 has 2 GB,
+partition 4 has x 4 GB, and partitions 2 and 3 use equal parts of the remaining
+storage. If the total amount of extended storage was 16 GB, then partitions 3 
+and 4 would each have approximately 5 GB.
+
+Module parameter syntax
++++++++++++++++++++++++
+XPRAM may be used as module. The syntax of the module parameters passed to
+insmod differs from the kernel parameter syntax:
+
+[devs=<number_of_devices> [sizes=<size>[,<size>,...]]]
+
+where:
+- number_of_devices is used to define the number of partitions.
+- size is a non-negative integer that defines the partition's size. 
+  Only decimal values are allowed and no magnitudes are accepted. 
+  The size will be interpretedin KB.
+
+Example
+-------
+
+devs=4 sizes=2097152,8388608,4194304,2097152
+
+This allocates a total of 16 GB of extended storage into four partitions, of
+(respectively) size 2 GB, 8 GB, 4 GB, and 2 GB.
+
+Usage
++++++
+
+XPRAM is a block device driver with major 35.
+Using the  standard naming scheme (see devices.txt) the partitions of XPRAM
+can be accessed through /dev/slram0, ... , /dev/slram31.
+
+XPRAM  does not require any formatting. Partitioning is only possible during
+device initialization by kernel or module parameters. Note that if both the
+expanded storage and the partitioning parameters are left unchanged between
+two device initializations (even if LINUX was IPLed in the meantime) then
+XPRAM behaves like a persistent storage. This is not true if the system is 
+IMLed.
+
+You can make a files system on a XPRAM partition (e.g. mke2fs) with a block 
+size that is a multiple of 4096 byte and mount this file system.
+
+Alternativly an XPRAM partition can be used as a swap device (mkswap, swapon).
\ No newline at end of file
diff -urN linux-2.2.18-pre20/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- linux-2.2.18-pre20/Documentation/usb/usb-serial.txt	Mon Dec  3 22:14:07 2001
+++ linux/Documentation/usb/usb-serial.txt	Mon Dec  3 22:14:15 2001
@@ -151,6 +151,37 @@
   driver.
 
 
+Belkin USB Serial Adapter F5U103
+
+  Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs.
+
+Current status:
+  The following have been tested and work:
+    Baud rate    300-230400               
+    Data bits    5-8
+    Stop bits    1-2
+    Parity       N,E,O,M,S
+    Handshake    None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)*
+    Break        Set and clear
+    Line contrl  Input/Output query and control **
+
+    *  Hardware input flow control is only enabled for firmware
+       levels above 2.06.  Read source code comments describing Belkin
+       firmware errata.  Hardware output flow control is working for all
+       firmware versions.
+    ** Queries of inputs (CTS,DSR,CD,RI) show the last
+       reported state.  Queries of outputs (DTR,RTS) show the last
+       requested state and may not reflect current state as set by
+       automatic hardware flow control.
+
+TO DO List:
+  -- Add true modem contol line query capability.  Currently tracks the
+     states reported by the interrupt and the states requested.
+  -- Add error reporting back to application for UART error conditions.
+  -- Add support for flush ioctls.
+  -- Add everything else that is missing :)
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
diff -urN linux-2.2.18-pre20/Makefile linux/Makefile
--- linux-2.2.18-pre20/Makefile	Mon Dec  3 22:14:07 2001
+++ linux/Makefile	Mon Dec  3 22:14:15 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 18
-EXTRAVERSION = pre20
+EXTRAVERSION = pre21
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -170,8 +170,8 @@
 DRIVERS := $(DRIVERS) drivers/net/fc/fc.a
 endif
 
-ifdef CONFIG_PPC
-DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
+ifdef CONFIG_POWERMAC
+DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.o
 endif
 
 ifdef CONFIG_PNP
diff -urN linux-2.2.18-pre20/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- linux-2.2.18-pre20/arch/i386/kernel/smp.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/i386/kernel/smp.c	Mon Dec  3 22:14:16 2001
@@ -364,13 +364,20 @@
 					(struct mpc_config_ioapic *)mpt;
 				if (m->mpc_flags&MPC_APIC_USABLE)
 				{
-					ioapics++;
-					printk("I/O APIC #%d Version %d at 0x%lX.\n",
-						m->mpc_apicid,m->mpc_apicver,
-						m->mpc_apicaddr);
-					mp_apics [mp_apic_entries] = *m;
-					if (++mp_apic_entries > MAX_IO_APICS)
-						--mp_apic_entries;
+					if(m->mpc_apicaddr == 0)
+					{
+						printk(KERN_ERR "Error - Non MP compliant BIOS. Skipping invalid io-apic!\n");
+					}
+					else
+					{
+						ioapics++;
+						printk("I/O APIC #%d Version %d at 0x%lX.\n",
+							m->mpc_apicid,m->mpc_apicver,
+							m->mpc_apicaddr);
+						mp_apics [mp_apic_entries] = *m;
+						if (++mp_apic_entries > MAX_IO_APICS)
+							--mp_apic_entries;
+					}
 				}
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
@@ -405,6 +412,12 @@
 	if (ioapics > MAX_IO_APICS)
 	{
 		printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics);
+		printk("Warning: switching to non APIC mode.\n");
+		skip_ioapic_setup=1;
+	}
+	if (ioapics == 0)
+	{
+		printk("Warning: BIOS table gives no I/O APIC.\n");
 		printk("Warning: switching to non APIC mode.\n");
 		skip_ioapic_setup=1;
 	}
diff -urN linux-2.2.18-pre20/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- linux-2.2.18-pre20/arch/ppc/boot/Makefile	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/boot/Makefile	Mon Dec  3 22:14:16 2001
@@ -10,7 +10,7 @@
 # modified by Cort (cort@cs.nmt.edu)
 #
 .c.s:
-	$(CC) $(CFLAGS) -S -o $*.s $<
+	$(CC) $(CFLAGS) -I$(HPATH) -S -o $*.s $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
diff -urN linux-2.2.18-pre20/arch/ppc/boot/vreset.c linux/arch/ppc/boot/vreset.c
--- linux-2.2.18-pre20/arch/ppc/boot/vreset.c	Thu May 21 14:24:05 1998
+++ linux/arch/ppc/boot/vreset.c	Mon Dec  3 22:14:16 2001
@@ -24,7 +24,7 @@
 extern char *vidmem;
 extern int lines, cols;
 /* estimate for delay */
-unsigned long loops_per_sec = 50000000;;
+unsigned long loops_per_jiffy = 50000000/HZ;
 /*
  * VGA Register  
  */
diff -urN linux-2.2.18-pre20/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- linux-2.2.18-pre20/arch/ppc/coffboot/Makefile	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/coffboot/Makefile	Mon Dec  3 22:14:16 2001
@@ -7,11 +7,11 @@
 
 CC	= $(CROSS_COMPILE)gcc
 LD	= $(CROSS_COMPILE)ld
-CFLAGS	= $(CPPFLAGS) -O -fno-builtin
+CFLAGS	= $(CPPFLAGS) -O -fno-builtin -I$(HPATH)
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
 COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
-CHRP_LD_ARGS = -Ttext 0x00400000
+CHRP_LD_ARGS = -Ttext 0x01000000
 GZ = gzip -9
 
 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
@@ -24,18 +24,13 @@
 MSIZE=
 endif
 
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build pmac stuff
-CONFIG_PMAC = y
-endif
-
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
 else
 TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE)
 endif
 
-ifeq ($(CONFIG_PMAC),y)
+ifeq ($(CONFIG_POWERMAC),y)
 hack-coff: hack-coff.c
 	$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
 
diff -urN linux-2.2.18-pre20/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c
--- linux-2.2.18-pre20/arch/ppc/coffboot/chrpmain.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/coffboot/chrpmain.c	Mon Dec  3 22:14:16 2001
@@ -18,13 +18,18 @@
 #define get_16be(x)	(*(unsigned short *)(x))
 #define get_32be(x)	(*(unsigned *)(x))
 
-#define RAM_START	0x00000000
-#define RAM_END		(8<<20)
+#define RAM_END		(16 << 20)
 
 #define PROG_START	0x00010000
+#define PROG_SIZE	0x003f0000
+
+#define SCRATCH_SIZE	(128 << 10)
 
 char *avail_ram;
-char *end_avail;
+char *begin_avail, *end_avail;
+char *avail_high;
+unsigned int heap_use;
+unsigned int heap_max;
 
 extern char _end[];
 extern char image_data[];
@@ -56,23 +61,28 @@
     im = image_data;
     len = image_len;
     /* claim 3MB starting at PROG_START */
-    claim(PROG_START, 3 << 20, 0);
+    claim(PROG_START, PROG_SIZE, 0);
     dst = (void *) PROG_START;
     if (im[0] == 0x1f && im[1] == 0x8b) {
-	/* claim 512kB for scratch space */
-	avail_ram = (char *) claim(0, 512 << 10, 0x10);
-	end_avail = avail_ram + (512 << 10);
-	printf("avail_ram = %x\n", avail_ram);
+	/* claim some memory for scratch space */
+	avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
+	begin_avail = avail_high = avail_ram;
+	end_avail = avail_ram + SCRATCH_SIZE;
+	printf("heap at 0x%x\n", avail_ram);
 	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
-	gunzip(dst, 3 << 20, im, &len);
+	gunzip(dst, PROG_SIZE, im, &len);
 	printf("done %u bytes\n", len);
+	printf("%u bytes of heap consumed, max in use %u\n",
+	       avail_high - begin_avail, heap_max);
     } else {
 	memmove(dst, im, len);
     }
 
     flush_cache(dst, len);
+#if 0
     stop_imac_ethernet();
     stop_imac_usb();
+#endif
 
     sa = (unsigned long)PROG_START;
     printf("start address = 0x%x\n", sa);
@@ -84,6 +94,7 @@
     pause();
 }
 
+#if 0
 #define eieio()	asm volatile("eieio");
 
 void stop_imac_ethernet(void)
@@ -134,14 +145,35 @@
     *usb_ctrl = 0x01000000;	/* cpu_to_le32(1) */
     eieio();
 }
+#endif
+
+struct memchunk {
+    unsigned int size;
+    struct memchunk *next;
+};
+
+static struct memchunk *freechunks;
 
 void *zalloc(void *x, unsigned items, unsigned size)
 {
-    void *p = avail_ram;
+    void *p;
+    struct memchunk **mpp, *mp;
 
     size *= items;
     size = (size + 7) & -8;
+    heap_use += size;
+    if (heap_use > heap_max)
+	heap_max = heap_use;
+    for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) {
+	if (mp->size == size) {
+	    *mpp = mp->next;
+	    return mp;
+	}
+    }
+    p = avail_ram;
     avail_ram += size;
+    if (avail_ram > avail_high)
+	avail_high = avail_ram;
     if (avail_ram > end_avail) {
 	printf("oops... out of memory\n");
 	pause();
@@ -151,6 +183,17 @@
 
 void zfree(void *x, void *addr, unsigned nb)
 {
+    struct memchunk *mp = addr;
+
+    nb = (nb + 7) & -8;
+    heap_use -= nb;
+    if (avail_ram == addr + nb) {
+	avail_ram = addr;
+	return;
+    }
+    mp->size = nb;
+    mp->next = freechunks;
+    freechunks = mp;
 }
 
 #define HEAD_CRC	2
diff -urN linux-2.2.18-pre20/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.2.18-pre20/arch/ppc/config.in	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/config.in	Mon Dec  3 22:14:16 2001
@@ -26,12 +26,12 @@
   bool 'Altivec (G4) support' CONFIG_ALTIVEC
 fi
 
-if [ "$CONFIG_ALL_PPC" != "y" ];then
+if [ "$CONFIG_ALL_PPC" != "y" ]; then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
 
-if [ "$CONFIG_PPC64" != "y" ];then
-  define_bool CONFIG_6xx y
+if [ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" ]; then
+  define_bool CONFIG_POWERMAC y
 fi
 endmenu
 
@@ -82,16 +82,7 @@
 
 bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
-
 bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK
-bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
-bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
-tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
-if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
-   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
-fi
-tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
-bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
 bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
 bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
 bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
@@ -182,7 +173,27 @@
 
 source drivers/char/Config.in
 source drivers/usb/Config.in
-source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Mac device drivers'
+if [ "$CONFIG_INPUT_KEYBDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "y" ]; then
+   bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID
+fi
+if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
+   define_bool CONFIG_MAC_HID y
+   bool '  Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
+   bool '  Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
+else
+   bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD
+   bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE
+fi
+tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
+bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
+tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
+endmenu
 
 mainmenu_option next_comment
 comment 'Sound'
@@ -193,6 +204,8 @@
 fi
 
 endmenu
+
+source fs/Config.in
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- linux-2.2.18-pre20/arch/ppc/kernel/Makefile	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/Makefile	Mon Dec  3 22:14:16 2001
@@ -36,20 +36,40 @@
 
 ifeq ($(CONFIG_MBX),y)
 O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
-else
+endif
 ifeq ($(CONFIG_APUS),y)
 O_OBJS += apus_setup.o prom.o openpic.o
-else
-ifneq ($(CONFIG_MBX),y)
-O_OBJS += prep_time.o pmac_time.o chrp_time.o \
-	  pmac_setup.o pmac_support.o \
-	  prep_pci.o pmac_pci.o chrp_pci.o \
-	  residual.o prom.o openpic.o feature.o \
-	  prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o \
-	  gemini_pci.o gemini_prom.o gemini_setup.o
-OX_OBJS += chrp_setup.o prep_setup.o
 endif
+
+PMAC_OBJS = pmac_time.o pmac_setup.o pmac_support.o pmac_pci.o pmac_pic.o \
+	feature.o openpic.o open_pic.o prom.o
+CHRP_OBJS = $(PMAC_OBJS) chrp_time.o chrp_pci.o i8259.o indirect_pci.o
+CHRPX_OBJS = chrp_setup.o
+PREP_OBJS = prep_time.o prep_pci.o residual.o prep_nvram.o i8259.o \
+	indirect_pci.o openpic.o open_pic.o prom.o
+PREPX_OBJS = prep_setup.o
+
+ifeq ($(CONFIG_ALL_PPC),y)
+O_OBJS += $(sort $(PMAC_OBJS) $(PREP_OBJS) $(CHRP_OBJS))
+OX_OBJS += $(PMACX_OBJS) $(PREPX_OBJS) $(CHRPX_OBJS)
+endif
+ifeq ($(CONFIG_PMAC),y)
+O_OBJS += $(PMAC_OBJS)
+OX_OBJS += $(PMACX_OBJS)
 endif
+ifeq ($(CONFIG_PREP),y)
+O_OBJS += $(PREP_OBJS)
+OX_OBJS += $(PREPX_OBJS)
+endif
+ifeq ($(CONFIG_CHRP),y)
+O_OBJS += $(CHRP_OBJS)
+OX_OBJS += $(CHRPX_OBJS)
+endif
+
+GEMINI_OBJS = $(PREP_OBJS) gemini_pci.o gemini_prom.o gemini_setup.o
+ifeq ($(CONFIG_GEMINI),y)
+O_OBJS += $(GEMINI_OBJS)
+OX_OBJS += $(PREPX_OBJS)
 endif
 
 ifdef CONFIG_SMP
@@ -75,7 +95,7 @@
 	$(HOSTCC) -o find_name find_name.c
 
 checks: checks.c
-	$(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c
+	$(HOSTCC) ${CFLAGS} -D__KERNEL__ -I../../../include -o checks checks.c
 	./checks
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/apus_setup.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/apus_setup.c	Mon Dec  3 22:14:16 2001
@@ -624,7 +624,7 @@
 	ppc_md.kbd_unexpected_up = NULL;
 	ppc_md.kbd_leds          = NULL;
 	ppc_md.kbd_init_hw       = NULL;
-	ppc_md.kbd_sysrq_xlate	 = NULL;
+	ppc_md.sysrq_xlate	 = NULL;
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
         ppc_ide_md.insw = apus_ide_insw;
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- linux-2.2.18-pre20/arch/ppc/kernel/chrp_pci.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/chrp_pci.c	Mon Dec  3 22:14:16 2001
@@ -19,6 +19,7 @@
 #include <asm/machdep.h>
 
 #include "pci.h"
+#include "open_pic.h"
 
 /* LongTrail */
 #define pci_config_addr(bus, dev, offset) \
@@ -286,7 +287,7 @@
 	for( dev=pci_devices ; dev; dev=dev->next )
 	{
 		if ( dev->irq )
-			dev->irq = openpic_to_irq( dev->irq );
+			dev->irq = dev->irq + open_pic.irq_offset;
 		/* these need to be absolute addrs for OF and Matrox FB -- Cort */
 		if ( dev->vendor == PCI_VENDOR_ID_MATROX )
 		{
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 22:14:16 2001
@@ -48,6 +48,7 @@
 #include <asm/irq.h>
 #include <asm/adb.h>
 #include <asm/hydra.h>
+#include <asm/keyboard.h>
 
 #include <asm/time.h>
 #include "local_irq.h"
@@ -68,7 +69,7 @@
 int chrp_set_rtc_time(unsigned long nowtime);
 unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0;
 void chrp_calibrate_decr(void);
-void chrp_time_init(void);
+long chrp_time_init(void);
 
 void chrp_setup_pci_ptrs(void);
 
@@ -95,6 +96,7 @@
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern int probingmem;
+extern unsigned long loops_per_jiffy;
 
 unsigned long empty_zero_page[1024];
 
@@ -357,81 +359,6 @@
 	}
 }
 
-void
-chrp_do_IRQ(struct pt_regs *regs,
-	    int            cpu,
-            int            isfake)
-{
-        int irq;
-        unsigned long bits = 0;
-        int openpic_eoi_done = 0;
-
-#ifdef __SMP__
-        {
-                unsigned int loops = 1000000;
-                while (test_bit(0, &global_irq_lock)) {
-                        if (smp_processor_id() == global_irq_holder) {
-                                printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
-                                xmon(0);
-#endif
-                                break;
-                        }
-                        if (loops-- == 0) {
-                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
-                                xmon(0);
-#endif
-                        }
-                }
-        }
-#endif /* __SMP__ */
-	
-        irq = openpic_irq(smp_processor_id());
-        if (irq == IRQ_8259_CASCADE)
-        {
-                /*
-                 * This magic address generates a PCI IACK cycle.
-                 *
-                 * This should go in the above mask/ack code soon. -- Cort
-                 */
-		if ( chrp_int_ack_special )
-			irq = *chrp_int_ack_special;
-		else
-			irq = i8259_irq(0);
-                /*
-                 * Acknowledge as soon as possible to allow i8259
-                 * interrupt nesting                         */
-                openpic_eoi(smp_processor_id());
-                openpic_eoi_done = 1;
-        }
-        if (irq == OPENPIC_VEC_SPURIOUS)
-        {
-                /*
-                 * Spurious interrupts should never be
-                 * acknowledged
-                 */
-                ppc_spurious_interrupts++;
-                openpic_eoi_done = 1;
-		goto out;
-        }
-        bits = 1UL << irq;
-
-        if (irq < 0)
-        {
-                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-                       irq, regs->nip);
-                ppc_spurious_interrupts++;
-        }
-	else
-        {
-		ppc_irq_dispatch_handler( regs, irq );
-	}
-out:
-        if (!openpic_eoi_done)
-                openpic_eoi(smp_processor_id());
-}
-
 __initfunc(void
 	   chrp_init_IRQ(void))
 {
@@ -446,7 +373,7 @@
 			(*(unsigned long *)get_property(np,
 							"8259-interrupt-acknowledge", NULL));
 	}
-	open_pic.irq_offset = 16;
+	open_pic.irq_offset = NUM_8259_INTERRUPTS;
 	for ( i = 16 ; i < NR_IRQS ; i++ )
 		irq_desc[i].ctl = &open_pic;
 	openpic_init(1);
@@ -454,7 +381,7 @@
 		irq_desc[i].ctl = &i8259_pic;
 	i8259_init();
 #ifdef CONFIG_XMON
-	request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+	request_irq(HYDRA_INT_ADB_NMI+open_pic.irq_offset,
 		    xmon_irq, 0, "NMI", 0);
 #endif	/* CONFIG_XMON */
 #ifdef __SMP__
@@ -487,8 +414,8 @@
 		ppc_md.kbd_leds          = pckbd_leds;
 		ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-		ppc_md.SYSRQ_KEY	 = 0x54;
+		ppc_md.sysrq_xlate	 = pckbd_sysrq_xlate;
+		SYSRQ_KEY		 = 0x54;
 #endif		
 	}
 	else
@@ -500,8 +427,8 @@
 		ppc_md.kbd_leds          = mackbd_leds;
 		ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
-		ppc_md.SYSRQ_KEY	 = 0x69;
+		ppc_md.sysrq_xlate	 = mackbd_sysrq_xlate;
+		SYSRQ_KEY		 = 0x69;
 #endif		
 	}
 #else
@@ -512,8 +439,8 @@
 	ppc_md.kbd_leds          = pckbd_leds;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	ppc_md.SYSRQ_KEY	 = 0x54;
+	ppc_md.sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY		 = 0x54;
 #endif
 #endif
 #endif
@@ -643,7 +570,7 @@
 	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
 	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
 	ppc_md.init_IRQ       = chrp_init_IRQ;
-	ppc_md.do_IRQ         = chrp_do_IRQ;
+	ppc_md.do_IRQ         = open_pic_do_IRQ;
 		
 	ppc_md.init           = chrp_init2;
 
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c
--- linux-2.2.18-pre20/arch/ppc/kernel/chrp_time.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/chrp_time.c	Mon Dec  3 22:14:16 2001
@@ -31,18 +31,19 @@
 static int nvram_as0 = NVRAM_AS0;
 static int nvram_data = NVRAM_DATA;
 
-__initfunc(void chrp_time_init(void))
+__initfunc(long chrp_time_init(void))
 {
 	struct device_node *rtcs;
 	int base;
 
 	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
 	if (rtcs == NULL || rtcs->addrs == NULL)
-		return;
+		return 0;
 	base = rtcs->addrs[0].address;
 	nvram_as1 = 0;
 	nvram_as0 = base;
 	nvram_data = base + 1;
+	return 0;
 }
 
 int chrp_cmos_clock_read(int addr)
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- linux-2.2.18-pre20/arch/ppc/kernel/feature.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/feature.c	Mon Dec  3 22:14:16 2001
@@ -2,16 +2,13 @@
  *  arch/ppc/kernel/feature.c
  *
  *  Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *                     Ben. Herrenschmidt (bh40@calva.net)
  *
  *  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.
  *
- *  BenH: Changed implementation to work on multiple registers
- * 	  polarity is also taken into account. Removed delay (now
- * 	  responsibility of the caller). Added spinlocks.
- *
  */
 #include <linux/types.h>
 #include <linux/init.h>
@@ -22,6 +19,8 @@
 #include <asm/errno.h>
 #include <asm/ohare.h>
 #include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/feature.h>
@@ -29,18 +28,30 @@
 #undef DEBUG_FEATURE
 
 #define MAX_FEATURE_CONTROLLERS		2
-#define MAX_FEATURE_OFFSET		0x50
+#define MAX_FEATURE_OFFSET		0x100
 #define FREG(c,r)			(&(((c)->reg)[(r)>>2]))
 
+/* Keylargo reg. access. */
+#define KL_FCR(r)	(keylargo_base + ((r) >> 2))
+#define KL_IN(r)	(in_le32(KL_FCR(r)))
+#define KL_OUT(r,v)	(out_le32(KL_FCR(r), (v)))
+#define KL_BIS(r,v)	(KL_OUT((r), KL_IN(r) | (v)))
+#define KL_BIC(r,v)	(KL_OUT((r), KL_IN(r) & ~(v)))
+
+/* Uni-N reg. access. Note that Uni-N regs are big endian */
+#define UN_REG(r)	(uninorth_base + ((r) >> 2))
+#define UN_IN(r)	(in_be32(UN_REG(r)))
+#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
+
 typedef struct feature_bit {
 	int		reg;		/* reg. offset from mac-io base */
 	unsigned int	polarity;	/* 0 = normal, 1 = inverse */
 	unsigned int	mask;		/* bit mask */
 } fbit;
 
-/* I don't have an OHare machine to test with, so I left those as they
- * were. Someone with such a machine chould check out what OF says and
- * try too see if they match the heathrow ones and should be changed too
+/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500)
  */
 static fbit feature_bits_ohare_pbook[] = {
 	{0x38,0,0},			/* FEATURE_null */
@@ -69,13 +80,48 @@
 	{0x38,0,0},			/* FEATURE_IDE2_reset */
 	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
 	{0x38,0,0},			/* FEATURE_Mediabay_content */
+	{0x38,0,0},			/* FEATURE_Airport_reset */
 };
 
-/* Those bits are from a PowerBook. It's possible that desktop machines
- * based on heathrow need a different definition or some bits removed
+/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed
+ * the SCC related bits and init them once. They have proven to occasionally cause
+ * problems with the desktop units.
  */
 static fbit feature_bits_heathrow[] = {
 	{0x38,0,0},			/* FEATURE_null */
+	{0x38,0,0},			/* FEATURE_Serial_reset */
+	{0x38,0,0},			/* FEATURE_Serial_enable */
+	{0x38,0,0},			/* FEATURE_Serial_IO_A */
+	{0x38,0,0},			/* FEATURE_Serial_IO_B */
+	{0x38,0,HRW_SWIM_ENABLE},	/* FEATURE_SWIM3_enable */
+	{0x38,0,HRW_MESH_ENABLE},	/* FEATURE_MESH_enable */
+	{0x38,0,HRW_IDE0_ENABLE},	/* FEATURE_IDE0_enable */
+	{0x38,1,HRW_IDE0_RESET_N},	/* FEATURE_IDE0_reset */
+	{0x38,0,HRW_IOBUS_ENABLE},	/* FEATURE_IOBUS_enable */
+	{0x38,1,0},			/* FEATURE_Mediabay_reset */
+	{0x38,1,0},			/* FEATURE_Mediabay_power */
+	{0x38,0,0},			/* FEATURE_Mediabay_PCI_enable */
+	{0x38,0,HRW_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,HRW_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
+	{0x38,0,0},			/* FEATURE_Mediabay_floppy_enable */
+	{0x38,0,HRW_BMAC_RESET},	/* FEATURE_BMac_reset */
+	{0x38,0,HRW_BMAC_IO_ENABLE},	/* FEATURE_BMac_IO_enable */
+	{0x38,1,0},			/* FEATURE_Modem_power */
+	{0x38,0,HRW_SLOW_SCC_PCLK},	/* FEATURE_Slow_SCC_PCLK */
+	{0x38,1,0},			/* FEATURE_Sound_Power */
+	{0x38,0,0},			/* FEATURE_Sound_CLK_Enable */
+	{0x38,0,0},			/* FEATURE_IDE2_enable */
+	{0x38,0,0},			/* FEATURE_IDE2_reset */
+	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
+	{0x38,0,0},			/* FEATURE_Mediabay_content */
+	{0x38,0,0},			/* FEATURE_Airport_reset */
+};
+
+/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet).
+ * Heathrow-based desktop macs (Beige G3s) are _not_ handled here
+ */
+static fbit feature_bits_wallstreet[] = {
+	{0x38,0,0},			/* FEATURE_null */
 	{0x38,0,HRW_RESET_SCC},		/* FEATURE_Serial_reset */
 	{0x38,0,HRW_SCC_ENABLE},	/* FEATURE_Serial_enable */
 	{0x38,0,HRW_SCCA_IO},		/* FEATURE_Serial_IO_A */
@@ -101,15 +147,17 @@
 	{0x38,0,0},			/* FEATURE_IDE2_reset */
 	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
 	{0x38,0,0},			/* FEATURE_Mediabay_content */
+	{0x38,0,0},			/* FEATURE_Airport_reset */
 };
 
 /*
  * Those bits are from a 1999 G3 PowerBook, with a paddington chip.
- * Mostly the same as the heathrow.
+ * Mostly the same as the heathrow. They are used on both PowerBooks
+ * and desktop machines using the paddington chip
  */
 static fbit feature_bits_paddington[] = {
 	{0x38,0,0},			/* FEATURE_null */
-	{0x38,0,0},			/* FEATURE_Serial_reset */
+	{0x38,0,PADD_RESET_SCC},	/* FEATURE_Serial_reset */
 	{0x38,0,HRW_SCC_ENABLE},	/* FEATURE_Serial_enable */
 	{0x38,0,HRW_SCCA_IO},		/* FEATURE_Serial_IO_A */
 	{0x38,0,HRW_SCCB_IO},		/* FEATURE_Serial_IO_B */
@@ -134,37 +182,40 @@
 	{0x38,0,0},			/* FEATURE_IDE2_reset */
 	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
 	{0x38,0,0},			/* FEATURE_Mediabay_content */
+	{0x38,0,0},			/* FEATURE_Airport_reset */
 };
 
 /* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
+ * Note: Different sets may be needed for iBook, especially for sound
  */
 static fbit feature_bits_keylargo[] = {
 	{0x38,0,0},			/* FEATURE_null */
-	{0x38,0,0},			/* FEATURE_Serial_reset */
-	{0x38,0,0x00000054},		/* FEATURE_Serial_enable */
-	{0x38,0,0},			/* FEATURE_Serial_IO_A */
-	{0x38,0,0},			/* FEATURE_Serial_IO_B */
+	{0x38,0,KL0_SCC_RESET},		/* FEATURE_Serial_reset */
+	{0x38,0,KL0_SERIAL_ENABLE},	/* FEATURE_Serial_enable */
+	{0x38,0,KL0_SCC_A_INTF_ENABLE},	/* FEATURE_Serial_IO_A */
+	{0x38,0,KL0_SCC_B_INTF_ENABLE},	/* FEATURE_Serial_IO_B */
 	{0x38,0,0},			/* FEATURE_SWIM3_enable */
 	{0x38,0,0},			/* FEATURE_MESH_enable */
 	{0x3c,0,0},			/* FEATURE_IDE0_enable */
- 	{0x3c,1,0x01000000},		/* FEATURE_IDE0_reset */
+ 	{0x3c,1,KL1_EIDE0_RESET_N},	/* FEATURE_IDE0_reset */
 	{0x38,0,0},			/* FEATURE_IOBUS_enable */
 	{0x34,1,0x00000200},		/* FEATURE_Mediabay_reset */
 	{0x34,1,0x00000400},		/* FEATURE_Mediabay_power */
 	{0x38,0,0},			/* FEATURE_Mediabay_PCI_enable */
 	{0x3c,0,0x0},			/* FEATURE_IDE1_enable */
-	{0x3c,1,0x08000000},		/* FEATURE_IDE1_reset */
+	{0x3c,1,KL1_EIDE1_RESET_N},	/* FEATURE_IDE1_reset */
 	{0x38,0,0},			/* FEATURE_Mediabay_floppy_enable */
 	{0x38,0,0},			/* FEATURE_BMac_reset */
 	{0x38,0,0},			/* FEATURE_BMac_IO_enable */
-	{0x40,1,0x02000000},		/* FEATURE_Modem_power */
+	{0x40,1,KL2_MODEM_POWER_N},	/* FEATURE_Modem_power */
 	{0x38,0,0},			/* FEATURE_Slow_SCC_PCLK */
 	{0x38,0,0},			/* FEATURE_Sound_Power */
 	{0x38,0,0},			/* FEATURE_Sound_CLK_Enable */
 	{0x38,0,0},			/* FEATURE_IDE2_enable */
-	{0x3c,1,0x40000000},		/* FEATURE_IDE2_reset */
-	{0x34,0,0x00001000},		/* FEATURE_Mediabay_IDE_switch */
+	{0x3c,1,KL1_UIDE_RESET_N},	/* FEATURE_IDE2_reset */
+	{0x34,0,KL_MBCR_MBDEV_ENABLE},	/* FEATURE_Mediabay_IDE_switch */
 	{0x34,0,0x00000100},		/* FEATURE_Mediabay_content */
+	{0x40,1,KL2_AIRPORT_RESET_N},	/* FEATURE_Airport_reset */
 };
 
 /* definition of a feature controller object */
@@ -176,33 +227,93 @@
 };
 
 /* static functions */
-static void
+static struct feature_controller*
 feature_add_controller(struct device_node *controller_device, fbit* bits);
 
 static struct feature_controller*
 feature_lookup_controller(struct device_node *device);
 
-/* static varialbles */
+static void uninorth_init(void);
+static void keylargo_init(void);
+#ifdef CONFIG_PMAC_PBOOK
+static void heathrow_prepare_for_sleep(struct feature_controller* ctrler);
+static void heathrow_wakeup(struct feature_controller* ctrler);
+static void core99_prepare_for_sleep(struct feature_controller* ctrler);
+static void core99_wake_up(struct feature_controller* ctrler);
+#endif /* CONFIG_PMAC_PBOOK */
+
+/* static variables */
 static struct feature_controller	controllers[MAX_FEATURE_CONTROLLERS];
 static int				controller_count = 0;
 
+/* Core99 stuffs */
+static volatile u32*			uninorth_base;
+static volatile u32*			keylargo_base;
+static struct feature_controller*	keylargo;
+static int				uninorth_rev;
+static int				keylargo_rev;
+static u32				board_features;
+
+#define FTR_NEED_OPENPIC_TWEAK		0x00000001
+
+static struct board_features_t {
+	char*	compatible;
+	u32	features;
+} board_features_datas[] __init = 
+{
+  {	"PowerMac2,1",		0				}, /* iMac ? */
+  {	"PowerMac2,2",		0				}, /* iMac ? */
+  {	"PowerMac3,1",		FTR_NEED_OPENPIC_TWEAK		}, /* Sawtooth (G4) */
+  {	"PowerMac3,3",		0				}, /* Dual G4 or Cube ? */
+  {	"PowerMac5,1",		0				}, /* Dual G4 or Cube ? */
+  {	"PowerBook2,1",		0				}, /* iBook */
+  {	"PowerBook2,2",		0				}, /* iBook FireWire ? */
+  {	"PowerBook3,1",		0				}, /* PowerBook 2000 (Pismo) */
+  {	NULL, 0 }
+};
 
 void
 feature_init(void)
 {
 	struct device_node *np;
+	u32* rev;
+	int i;
+	
+	/* Figure out motherboard type & options */
+	for(i=0;board_features_datas[i].compatible;i++)
+		if (machine_is_compatible(board_features_datas[i].compatible)) {
+			board_features = board_features_datas[i].features;
+			break;
+		}
 
+	/* Track those poor mac-io's */
+	
 	np = find_devices("mac-io");
 	while (np != NULL) {
 		/* KeyLargo contains several (5 ?) FCR registers in mac-io,
 		 * plus some gpio's which could eventually be handled here.
 		 */
 		if (device_is_compatible(np, "Keylargo")) {
-			feature_add_controller(np, feature_bits_keylargo);
+			struct feature_controller* ctrler =
+				feature_add_controller(np, feature_bits_keylargo);
+			if (ctrler) {
+				keylargo = ctrler;
+				keylargo_base = ctrler->reg;
+				rev = (u32 *)get_property(ctrler->device, "revision-id", NULL);
+				if (rev)
+					keylargo_rev = *rev;
+			}
 		} else if (device_is_compatible(np, "paddington")) {
 			feature_add_controller(np, feature_bits_paddington);
+		} else if (machine_is_compatible("AAPL,PowerBook1998")) {
+			feature_add_controller(np, feature_bits_wallstreet);
 		} else {
-			feature_add_controller(np, feature_bits_heathrow);
+			struct feature_controller* ctrler =
+				feature_add_controller(np, feature_bits_heathrow);
+			if (ctrler)
+				out_le32(FREG(ctrler,HEATHROW_FEATURE_REG),
+					in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS);
+			
 		}
 		np = np->next;
 	}
@@ -218,6 +329,20 @@
 		}
 	}
 
+	/* Locate core99 Uni-N */
+	np = find_devices("uni-n");
+	if (np && np->n_addrs > 0) {
+		uninorth_base = ioremap(np->addrs[0].address, 0x1000);
+		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+	}
+	if (uninorth_base && keylargo_base)
+		printk("Uni-N revision: %d, KeyLargo revision: %d\n",
+			uninorth_rev, keylargo_rev);
+	if (uninorth_base)
+		uninorth_init();
+	if (keylargo_base)
+		keylargo_init();
+
 	if (controller_count)
 		printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
 
@@ -232,7 +357,7 @@
 #endif
 }
 
-static void
+static struct feature_controller*
 feature_add_controller(struct device_node *controller_device, fbit* bits)
 {
 	struct feature_controller*	controller;
@@ -240,7 +365,7 @@
 	if (controller_count >= MAX_FEATURE_CONTROLLERS) {
 		printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
 			controller_device->full_name, MAX_FEATURE_CONTROLLERS);
-		return;
+		return NULL;
 	}
 	controller = &controllers[controller_count];
 
@@ -249,21 +374,27 @@
 	if (controller_device->n_addrs == 0) {
 		printk(KERN_ERR "No addresses for %s\n",
 			controller_device->full_name);
-		return;
+		return NULL;
 	}
 
+	/* We remap the entire mac-io here. Normally, this will just
+	 * give us back our already existing BAT mapping
+	 */
 	controller->reg		= (volatile u32 *)ioremap(
-		controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
+		controller_device->addrs[0].address,
+		controller_device->addrs[0].size);
 
 	if (bits == NULL) {
 		printk(KERN_INFO "Twiddling the magic ohare bits\n");
 		out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
-		return;
+		return NULL;
 	}
 
 	spin_lock_init(&controller->lock);
 	
 	controller_count++;
+
+	return controller;
 }
 
 static struct feature_controller*
@@ -383,5 +514,371 @@
 	 */
 	value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
 	return bit->polarity ? (value == 0) : (value == bit->mask);
+}
+
+/*
+ * Core99 functions
+ * 
+ * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo
+ *       chip, which is the case on all Core99 machines so far
+ */
+
+/* Only one GMAC is assumed */
+void
+feature_set_gmac_power(struct device_node* device, int power)
+{
+	unsigned long flags;
+	
+	if (!uninorth_base || !keylargo)
+		return;
+		
+	spin_lock_irqsave(&keylargo->lock, flags);
+	if (power)
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+	else
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+	spin_unlock_irqrestore(&keylargo->lock, flags);
+	udelay(20);
+}
+
+void
+feature_set_gmac_phy_reset(struct device_node* device, int reset)
+{
+	unsigned long flags;
+	
+	if (!keylargo_base || !keylargo)
+		return;
+		
+	spin_lock_irqsave(&keylargo->lock, flags);
+	out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset);
+	(void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET));
+	spin_unlock_irqrestore(&keylargo->lock, flags);
+}
+
+/* Pass the node of the correct controller, please */
+void
+feature_set_usb_power(struct device_node* device, int power)
+{
+	char* prop;
+	int number;
+	u32 reg;
+	
+	unsigned long flags;
+	
+	if (!keylargo_base || !keylargo)
+		return;
+		
+	prop = (char *)get_property(device, "AAPL,clock-id", NULL);
+	if (!prop)
+		return;
+	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+		number = 0;
+	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+		number = 2;
+	else
+		return;
+	
+	spin_lock_irqsave(&keylargo->lock, flags);
+	if (power) {
+		/* Turn ON */
+			
+		if (number == 0) {
+			KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			mdelay(1);
+			KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+		} else {
+			KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			mdelay(1);
+			KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+		}
+		reg = KL_IN(KEYLARGO_FCR4);
+		reg &=	~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
+			KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number));
+		reg &=	~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
+			KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1));
+		KL_OUT(KEYLARGO_FCR4, reg);
+		(void)KL_IN(KEYLARGO_FCR4);
+		udelay(10);
+	} else {
+		/* Turn OFF */
+		
+		reg = KL_IN(KEYLARGO_FCR4);
+		reg |=	KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
+			KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number);
+		reg |=	KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
+			KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1);
+		KL_OUT(KEYLARGO_FCR4, reg);
+		(void)KL_IN(KEYLARGO_FCR4);
+		udelay(1);
+		if (number == 0) {
+			KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+			(void)KL_IN(KEYLARGO_FCR0);
+			udelay(1);
+			KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			(void)KL_IN(KEYLARGO_FCR0);
+		} else {
+			KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+			(void)KL_IN(KEYLARGO_FCR0);
+			udelay(1);
+			KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			(void)KL_IN(KEYLARGO_FCR0);
+		}
+		udelay(1);
+	}
+	spin_unlock_irqrestore(&keylargo->lock, flags);
+}
+
+/* Not yet implemented */
+void 
+feature_set_firewire_power(struct device_node* device, int power)
+{
+}
+
+#ifdef CONFIG_SMP
+void
+feature_core99_kick_cpu1(void)
+{
+	out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT);
+	udelay(1);
+	out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE);
+}
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PMAC_PBOOK
+void
+feature_prepare_for_sleep(void)
+{
+	/* We assume gatwick is second */
+	struct feature_controller* ctrler = &controllers[0];
+
+	if (!ctrler)
+		return;
+	if (controller_count > 1 &&
+		device_is_compatible(ctrler->device, "gatwick"))
+		ctrler = &controllers[1];
+
+	if (ctrler->bits == feature_bits_heathrow ||
+		ctrler->bits == feature_bits_paddington) {
+		heathrow_prepare_for_sleep(ctrler);
+		return;
+	}
+	if (ctrler->bits == feature_bits_keylargo) {
+		core99_prepare_for_sleep(ctrler);
+		return;
+	}
+}
+
+
+void
+feature_wake_up(void)
+{
+	struct feature_controller* ctrler = &controllers[0];
+
+	if (!ctrler)
+		return;
+	if (controller_count > 1 &&
+		device_is_compatible(ctrler->device, "gatwick"))
+		ctrler = &controllers[1];
+	
+	if (ctrler->bits == feature_bits_heathrow ||
+		ctrler->bits == feature_bits_paddington) {
+		heathrow_wakeup(ctrler);
+		return;
+	}
+	if (ctrler->bits == feature_bits_keylargo) {
+		core99_wake_up(ctrler);
+		return;
+	}
+}
+
+static u32 save_fcr[5];
+static u32 save_mbcr;
+static u32 save_gpio_levels[2];
+static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
+static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
+
+static void
+heathrow_prepare_for_sleep(struct feature_controller* ctrler)
+{
+	save_mbcr = in_le32(FREG(ctrler, 0x34));
+	save_fcr[0] = in_le32(FREG(ctrler, 0x38));
+	save_fcr[1] = in_le32(FREG(ctrler, 0x3c));
+
+	out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE);
+}
+
+static void
+heathrow_wakeup(struct feature_controller* ctrler)
+{
+	out_le32(FREG(ctrler, 0x38), save_fcr[0]);
+	out_le32(FREG(ctrler, 0x3c), save_fcr[1]);
+	out_le32(FREG(ctrler, 0x34), save_mbcr);
+	mdelay(1);
+	out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE);
+	mdelay(1);
+}
+
+
+static void
+core99_prepare_for_sleep(struct feature_controller* ctrler)
+{
+	u32 temp;
+	int i;
+	u8* base8;
+	
+	/*
+	 * Save various bits of KeyLargo
+	 */
+
+	save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0);
+	save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1);
+	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+		save_gpio_extint[i] = in_8(base8+i);
+	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+		save_gpio_normal[i] = in_8(base8+i);
+	save_mbcr = KL_IN(KEYLARGO_MBCR);
+	save_fcr[0] = KL_IN(KEYLARGO_FCR0);
+	save_fcr[1] = KL_IN(KEYLARGO_FCR1);
+	save_fcr[2] = KL_IN(KEYLARGO_FCR2);
+	save_fcr[3] = KL_IN(KEYLARGO_FCR3);
+	save_fcr[4] = KL_IN(KEYLARGO_FCR4);
+
+	/*
+	 * Turn off as much as we can
+	 */
+	 
+	KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+	mdelay(1);	
+	KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | KL0_SCC_CELL_ENABLE);
+	KL_BIC(KEYLARGO_FCR0, KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+
+	KL_BIS(KEYLARGO_MBCR, KL_MBCR_MBDEV_ENABLE);
+
+	KL_BIC(KEYLARGO_FCR1,
+		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
+		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
+		KL1_UIDE_ENABLE);
+
+	KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+	KL_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+
+	temp = KL_IN(KEYLARGO_FCR3);
+	if (keylargo_rev >= 2)
+		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
+		
+	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	KL_OUT(KEYLARGO_FCR3, temp);
+
+	/* 
+	 * Put the host bridge to sleep
+	 */
+	 
+	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+
+	/*
+	 * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+	 */
+	if (board_features & FTR_NEED_OPENPIC_TWEAK) {
+		KL_BIS(0x506e0, 0x00400000);
+		KL_BIS(0x506e0, 0x80000000);
+	}
+}
+
+static void
+core99_wake_up(struct feature_controller* ctrler)
+{
+	int i;
+	u8* base8;
+
+	/*
+	 * Wakeup the host bridge
+	 */
+	UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+	UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+
+	/*
+	 * Restore KeyLargo
+	 */
+	 
+	KL_OUT(KEYLARGO_MBCR, save_mbcr);
+	KL_OUT(KEYLARGO_FCR0, save_fcr[0]);
+	KL_OUT(KEYLARGO_FCR1, save_fcr[1]);
+	KL_OUT(KEYLARGO_FCR2, save_fcr[2]);
+	KL_OUT(KEYLARGO_FCR3, save_fcr[3]);
+	KL_OUT(KEYLARGO_FCR4, save_fcr[4]);
+	mdelay(1);
+	KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+	KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+		out_8(base8+i, save_gpio_extint[i]);
+	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+		out_8(base8+i, save_gpio_normal[i]);
+
+	/* FIXME more black magic with OpenPIC ... */
+	if (board_features & FTR_NEED_OPENPIC_TWEAK) {
+		KL_BIC(0x506e0, 0x00400000);
+		KL_BIC(0x506e0, 0x80000000);
+	}
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void
+uninorth_init(void)
+{
+	struct device_node* gmac;
+	unsigned long actrl;
+	
+	/* Set the arbitrer QAck delay according to what Apple does
+	 */
+	actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
+	actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY)
+		<< UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+	UN_OUT(UNI_N_ARB_CTRL, actrl);
+	
+	/* 
+	 * Turns OFF the gmac clock. The gmac driver will turn
+	 * it back ON when the interface is enabled. This save
+	 * power on portables.
+	 * 
+	 * Note: We could also try to turn OFF the PHY. Since this
+	 * has to be done by both the gmac driver and this code,
+	 * I'll probably end-up moving some of this out of the
+	 * modular gmac driver into a non-modular stub containing
+	 * some basic PHY management and power management stuffs
+	 */
+	gmac = find_devices("ethernet");
+
+	while(gmac) {
+		if (device_is_compatible(gmac, "gmac"))
+			break;
+		gmac = gmac->next;
+	}
+	if (gmac)
+		feature_set_gmac_power(gmac, 0);
+}
+
+/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure
+ * OpenPIC is enabled
+ */
+static void
+keylargo_init(void)
+{
+	KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE);
 }
 
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/gemini_setup.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/gemini_setup.c	Mon Dec  3 22:14:16 2001
@@ -30,6 +30,7 @@
 #include <asm/io.h>
 #include <asm/m48t35.h>
 #include <asm/gemini.h>
+#include <asm/processor.h>
 
 #include <asm/time.h>
 #include "local_irq.h"
@@ -257,14 +258,6 @@
 	return clock;
 }
 
-
-#define L2CR_PIPE_LATEWR   (0x01800000)   /* late-write SRAM */
-#define L2CR_L2CTL         (0x00100000)   /* RAM control */
-#define L2CR_INST_DISABLE  (0x00400000)   /* disable for insn's */
-#define L2CR_L2I           (0x00200000)   /* global invalidate */
-#define L2CR_L2E           (0x80000000)   /* enable */
-#define L2CR_L2WT          (0x00080000)   /* write-through */
-
 void __init gemini_init_l2(void)
 {
 	unsigned char reg;
@@ -338,8 +331,7 @@
 			cache |= L2CR_L2WT;
 #endif
 		cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE;
-		_set_L2CR(0);
-		_set_L2CR(cache|L2CR_L2I|L2CR_L2E);
+		_set_L2CR(cache|L2CR_L2E);
 	}
 }
 
@@ -389,7 +381,7 @@
 #define gemini_rtc_write(val,x)  (writeb((val),(GEMINI_RTC+(x))))
 
 /* ensure that the RTC is up and running */
-void __init gemini_time_init(void)
+long __init gemini_time_init(void)
 {
 	unsigned char reg;
 
@@ -400,6 +392,7 @@
 		gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
 		gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
 	}
+	return 0;
 }
 
 #undef DEBUG_RTC
@@ -570,6 +563,6 @@
 	ppc_md.kbd_leds = NULL;
 	ppc_md.kbd_init_hw = NULL;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate = NULL;
+	ppc_md.sysrq_xlate = NULL;
 #endif
 }
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- linux-2.2.18-pre20/arch/ppc/kernel/head.S	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/head.S	Mon Dec  3 22:14:16 2001
@@ -23,6 +23,10 @@
  *  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.
+ *
+ *  2000-04-10.
+ *  Add sys_rt_sigreturn in DoSyscall Handler.
+ *  Giovanna Ambrosini (ambrosini@lightning.ch).
  *	
  */
 
@@ -258,66 +262,15 @@
 __secondary_start:
 /* Switch MMU off, clear BATs and flush TLB */
  	bl	mmu_off
+mmu_off_return:
 	bl	clear_bats
 	bl	flush_tlbs
-
-/* Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to KERNELBASE.  From this point on we can't safely
- * call OF any more.
- */
-	lis	r11,KERNELBASE@h
-	mfspr	r9,PVR
-	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
-	cmpi	0,r9,1
-	bne	4f
-	ori	r11,r11,4		/* set up BAT registers for 601 */
-	li	r8,0x7f			/* valid, block length = 8MB */
-	oris	r9,r11,0x800000@h	/* set up BAT reg for 2nd 8M */
-	oris	r10,r8,0x800000@h	/* set up BAT reg for 2nd 8M */
-	mtspr	IBAT0U,r11		/* N.B. 601 has valid bit in */
-	mtspr	IBAT0L,r8		/* lower BAT register */
-	mtspr	IBAT1U,r9
-	mtspr	IBAT1L,r10
-	b	5f
-4:
-#ifdef CONFIG_APUS
-	ori	r11,r11,BL_8M<<2|0x2	/* set up an 8MB mapping */
-	ori	r11,r11,0xfe		/* set up an 8MB mapping */
-	lis	r8,CYBERBASEp@h
-	lwz	r8,0(r8)
-	addis	r8,r8,KERNELBASE@h
-	addi	r8,r8,2
-#else	
-	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
-	li	r8,2			/* R/W access */
-	/*
-	 * If the MMU is off clear the bats.  See clear_bat() -- Cort
-	 */
-#ifndef CONFIG_GEMINI	
-	/* 
-	 * allow secondary cpus to get at all of ram in early bootup
-	 * since their init_task may be up there -- Cort
-	 */
-	oris	r18,r8,0x10000000@h
-	oris	r21,r11,(KERNELBASE+0x10000000)@h
-	mtspr	DBAT1L,r18		/* N.B. 6xx (not 601) have valid */
-	mtspr	DBAT1U,r21		/* bit in upper BAT register */
-	mtspr	IBAT1L,r18
-	mtspr	IBAT1U,r21
-	
-	oris	r18,r8,0x20000000@h
-	oris	r21,r11,(KERNELBASE+0x20000000)@h
-	mtspr	DBAT2L,r18		/* N.B. 6xx (not 601) have valid */
-	mtspr	DBAT2U,r21		/* bit in upper BAT register */
-	mtspr	IBAT2L,r18
-	mtspr	IBAT2U,r21
-#endif /* ndef CONFIG_GEMINI */	
+	bl	setup_init_bats
+#ifndef CONFIG_APUS
+#ifdef CONFIG_BOOTX_TEXT
+	bl	setup_disp_bat
+#endif
 #endif
-	mtspr	DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
-	mtspr	DBAT0U,r11		/* bit in upper BAT register */
-	mtspr	IBAT0L,r8
-	mtspr	IBAT0U,r11
-5:	isync
 #ifdef CONFIG_APUS
 	/* Unfortunately the APUS specific instructions bloat the
 	 * code so it cannot fit in the 0x100 bytes available. We have
@@ -443,6 +396,15 @@
 #endif /* CONFIG_8xx */
 	b	turn_on_mmu
 
+/* Hack for sleep on Core99 machines
+ */
+#ifdef CONFIG_POWERMAC
+	. = 0x80
+SleepVector:
+	.long	0
+	.long	0	
+#endif /* CONFIG_POWERMAC */
+
 /*
  * GCC sometimes accesses words at negative offsets from the stack
  * pointer, although the SysV ABI says it shouldn't.  To cope with
@@ -515,7 +477,7 @@
 #endif /* CONFIG_GEMINI */
 #else
 	STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif	
+#endif
 
 /* Machine check */
 	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -1383,11 +1345,7 @@
 	/* Construct the high word of the PPC-style PTE */
 	mfsrin	r5,r3			/* get segment reg for segment */
 	rlwinm	r5,r5,7,1,24		/* put VSID in 0x7fffff80 bits */
-	
-#ifndef __SMP__				/* do this later for SMP */
 	oris	r5,r5,0x8000		/* set V (valid) bit */
-#endif
-	
 	rlwimi	r5,r3,10,26,31		/* put in API (abbrev page index) */
 	/* Get the address of the primary PTE group in the hash table */
 	.globl	hash_page_patch_A
@@ -1499,6 +1457,7 @@
  */
 found_empty:
 found_slot:
+	clrlwi	r5,r5,1		/* clear valid bit (0x80000000) */
 	stw	r5,0(r3)	/* clear V (valid) bit in PTE */
 	sync
 	tlbsync
@@ -1819,14 +1778,8 @@
 	blr
 #endif /* CONFIG_ALTIVEC */
 
-#else  /* CONFIG_8xx */
-	.globl	giveup_fpu
-giveup_fpu:
-	blr
-#endif /* CONFIG_8xx */
-
 mmu_off:
- 	addi	r4, r3, __secondary_start - _start
+ 	addi	r4, r3, mmu_off_return - _start
 	mfmsr	r3
 	andi.	r0,r3,MSR_DR|MSR_IR		/* MMU enabled? */
 	beqlr
@@ -1892,6 +1845,12 @@
 	. = 0x4000
 #endif
 
+#else  /* CONFIG_8xx */
+	.globl	giveup_fpu
+giveup_fpu:
+	blr
+#endif /* CONFIG_8xx */
+
 turn_on_mmu:
 	mfmsr	r0
 	ori	r1,r0,MSR_DR|MSR_IR
@@ -1984,6 +1943,7 @@
 	cror	14,14,18
 	bne	3,6f
 	ori	r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */
+	rlwinm	r11,r11,0,23,21		/* clear HID0_SPD */
  	li	r3,0
  	mtspr	ICTC,r3
 5:	mtspr	HID0,r11		/* superscalar exec & br history tbl */
@@ -2166,7 +2126,9 @@
 1:
 #endif /* SHOW_SYSCALLS */
 	cmpi	0,r0,0x7777	/* Special case for 'sys_sigreturn' */
+        cmpi    1,r0,0x6666     /* Special case for 'sys_rt_sigreturn' */
 	beq-	10f
+        beq-    cr1,16f
 	lwz	r10,TASK_FLAGS(r2)
 	andi.	r10,r10,PF_TRACESYS
 	bne-	50f
@@ -2213,6 +2175,12 @@
 /* sys_sigreturn */
 10:	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	sys_sigreturn
+        cmpi    0,r3,0          /* Check for restarted system call */
+        bge     int_return
+        b       20b
+/* sys_rt_sigreturn */
+16:     addi    r3,r1,STACK_FRAME_OVERHEAD
+        bl      sys_rt_sigreturn
 	cmpi	0,r3,0		/* Check for restarted system call */
 	bge	int_return
 	b	20b
@@ -2883,30 +2851,6 @@
        mtlr    r4
        blr
 #endif /* CONFIG_8xx */
-	
-/*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
- */
-	.data
-	.globl	sdata
-sdata:
-	.globl	empty_zero_page
-empty_zero_page:
-	.space	4096
-
-	.globl	swapper_pg_dir
-swapper_pg_dir:
-	.space	4096	
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */	
-	.globl	cmd_line
-cmd_line:
-	.space	512
 
 /* 
  * An undocumented "feature" of 604e requires that the v bit
@@ -2951,4 +2895,117 @@
 	blt	1b
 	sync
 	blr
+
+/* Use the first pair of BAT registers to map the 1st 16MB
+ * of RAM to KERNELBASE.  From this point on we can't safely
+ * call OF any more.
+ */
+setup_init_bats:
+	lis	r11,KERNELBASE@h
+	mfspr	r9,PVR
+	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
+	cmpi	0,r9,1
+	bne	4f
+	ori	r11,r11,4		/* set up BAT registers for 601 */
+	li	r8,0x7f			/* valid, block length = 8MB */
+	oris	r9,r11,0x800000@h	/* set up BAT reg for 2nd 8M */
+	oris	r10,r8,0x800000@h	/* set up BAT reg for 2nd 8M */
+	mtspr	IBAT0U,r11		/* N.B. 601 has valid bit in */
+	mtspr	IBAT0L,r8		/* lower BAT register */
+	mtspr	IBAT1U,r9
+	mtspr	IBAT1L,r10
+	b	5f
+4:
+#ifdef CONFIG_APUS
+	ori	r11,r11,BL_8M<<2|0x2	/* set up an 8MB mapping */
+	ori	r11,r11,0xfe		/* set up an 8MB mapping */
+	lis	r8,CYBERBASEp@h
+	lwz	r8,0(r8)
+	addis	r8,r8,KERNELBASE@h
+	addi	r8,r8,2
+#else	
+	ori	r11,r11,BL_256M<<2|0x2	/* set up BAT registers for 604 */
+	li	r8,2			/* R/W access */
+	/*
+	 * If the MMU is off clear the bats.  See clear_bat() -- Cort
+	 */
+#ifndef CONFIG_GEMINI	
+	/* 
+	 * allow secondary cpus to get at all of ram in early bootup
+	 * since their init_task may be up there -- Cort
+	 */
+	oris	r18,r8,0x10000000@h
+	oris	r21,r11,(KERNELBASE+0x10000000)@h
+	mtspr	DBAT1L,r18		/* N.B. 6xx (not 601) have valid */
+	mtspr	DBAT1U,r21		/* bit in upper BAT register */
+	mtspr	IBAT1L,r18
+	mtspr	IBAT1U,r21
 	
+	oris	r18,r8,0x20000000@h
+	oris	r21,r11,(KERNELBASE+0x20000000)@h
+	mtspr	DBAT2L,r18		/* N.B. 6xx (not 601) have valid */
+	mtspr	DBAT2U,r21		/* bit in upper BAT register */
+	mtspr	IBAT2L,r18
+	mtspr	IBAT2U,r21
+#endif /* ndef CONFIG_GEMINI */	
+#endif
+	mtspr	DBAT0L,r8		/* N.B. 6xx (not 601) have valid */
+	mtspr	DBAT0U,r11		/* bit in upper BAT register */
+	mtspr	IBAT0L,r8
+	mtspr	IBAT0U,r11
+5:	isync
+	blr
+	
+#ifdef CONFIG_BOOTX_TEXT
+setup_disp_bat:
+	/*
+	 * setup the display bat prepared for us in prom.c
+	 */
+	mflr	r8
+	bl	reloc_offset
+	mtlr	r8
+	lis	r8, disp_BATL@h
+	ori	r8, r8, disp_BATL@l
+	add	r8, r3, r8
+	lwz	r8, 0(r8)
+	lis	r11, disp_BATU@h
+	ori	r11, r11, disp_BATU@l
+	add	r11, r3, r11
+	lwz	r11, 0(r11)
+	mtspr	IBAT3L,r8
+	mtspr	IBAT3U,r11
+	mfspr	r9,PVR
+	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
+	cmpi	0,r9,1
+	beq	1f
+	mtspr	DBAT3L,r8
+	mtspr	DBAT3U,r11
+1:		
+	blr
+#endif
+	
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
+	.data
+	.globl	sdata
+sdata:
+	.globl	empty_zero_page
+empty_zero_page:
+	.space	4096
+
+	.globl	swapper_pg_dir
+swapper_pg_dir:
+	.space	4096	
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * Used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */	
+	.globl	cmd_line
+cmd_line:
+	.space	512
+
+
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- linux-2.2.18-pre20/arch/ppc/kernel/irq.c	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/irq.c	Mon Dec  3 22:14:16 2001
@@ -61,7 +61,9 @@
 
 #include "local_irq.h"
 
-extern volatile unsigned long ipi_count;
+extern atomic_t ipi_recv;
+extern atomic_t ipi_sent;
+void enable_irq(unsigned int irq_nr);
 void enable_irq(unsigned int irq_nr);
 void disable_irq(unsigned int irq_nr);
 
@@ -137,20 +139,21 @@
 	if (!handler)
 	{
 		/* Free */
-		for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
-		{
-			if (action->dev_id == dev_id)
-			{
-				/* Found it - now free it */
-				save_flags(flags);
-				cli();
-				*p = action->next;
-				restore_flags(flags);
-				irq_kfree(action);
-				return 0;
-			}
-		}
-		return -ENOENT;
+		p = &irq_desc[irq].action;
+		while ((action = *p) != NULL && action->dev_id != dev_id)
+			p = &action->next;
+		if (action == NULL)
+			return -ENOENT;
+
+		/* Found it - now free it */
+		save_flags(flags);
+		cli();
+		*p = action->next;
+		if (irq_desc[irq].action == NULL)
+			disable_irq(irq);
+		restore_flags(flags);
+		irq_kfree(action);
+		return 0;
 	}
 	
 	action = (struct irqaction *)
@@ -241,8 +244,10 @@
 	}
 #ifdef __SMP__
 	/* should this be per processor send/receive? */
-	len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
-#endif		
+  	/* should this be per processor send/receive? */
+ 	len += sprintf(buf+len, "IPI: (recv/sent) %10lu/%lu\n",
+ 			atomic_read(&ipi_recv), atomic_read(&ipi_sent));
+#endif /* __SMP__ */		
 	len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
 	return len;
 }
@@ -317,10 +322,14 @@
 atomic_t global_bh_count;
 atomic_t global_bh_lock;
 
+extern unsigned long *_get_SP(void);
+
 static void show(char * str)
 {
+#if 0
 	int i;
 	unsigned long *stack;
+#endif
 	int cpu = smp_processor_id();
 
 	printk("\n%s, CPU %d:\n", str, cpu);
@@ -332,6 +341,10 @@
 	       atomic_read(&global_bh_count),
 	       ppc_local_bh_count[0],
 	       ppc_local_bh_count[1]);
+#if 1
+	printk(" CPU: %d last CPU: %d\n", current->processor,current->last_processor);
+	print_backtrace (_get_SP());
+#else
 	stack = (unsigned long *) &str;
 	for (i = 40; i ; i--) {
 		unsigned long x = *++stack;
@@ -339,6 +352,7 @@
 			printk("<[%08lx]> ", x);
 		}
 	}
+#endif
 }
 
 static inline void wait_on_bh(void)
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/mbx_pci.c linux/arch/ppc/kernel/mbx_pci.c
--- linux-2.2.18-pre20/arch/ppc/kernel/mbx_pci.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/mbx_pci.c	Mon Dec  3 22:14:16 2001
@@ -17,7 +17,9 @@
 
 #include <asm/io.h>
 #include <asm/mbx.h>
+#include <asm/machdep.h>
 
+#include "pci.h"
 
 /*
  * This blows......The MBX uses the Tundra QSpan PCI bridge.  When
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/mbx_setup.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/mbx_setup.c	Mon Dec  3 22:14:16 2001
@@ -41,14 +41,25 @@
 #include <asm/ide.h>
 #include <asm/mbx.h>
 #include <asm/machdep.h>
-
+#include <asm/keyboard.h>
+#include <asm/8xx_immap.h>
 #include <asm/time.h>
+
 #include "local_irq.h"
 
 static int mbx_set_rtc_time(unsigned long time);
 unsigned long mbx_get_rtc_time(void);
 void mbx_calibrate_decr(void);
 
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
 extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int mackbd_getkeycode(unsigned int scancode);
 extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -452,8 +463,8 @@
 	ppc_md.kbd_leds          = pckbd_leds;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	ppc_md.SYSRQ_KEY	 = 0x54;
+	ppc_md.sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY		 = 0x54;
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- linux-2.2.18-pre20/arch/ppc/kernel/misc.S	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/misc.S	Mon Dec  3 22:14:16 2001
@@ -125,12 +125,33 @@
  * Flush MMU TLB
  */
 _GLOBAL(_tlbia)
+#if defined(CONFIG_SMP)
+	mfmsr	r10
+	sync
+	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	mtmsr	r0
+	SYNC
+	lis	r9,hash_table_lock@h
+	ori	r9,r9,hash_table_lock@l
+	lwz	r8,PROCESSOR(r2)
+	oris	r8,r8,10
+10:	lwarx	r7,0,r9
+	cmpi	0,r7,0
+	bne-	10b
+	stwcx.	r8,0,r9
+	bne-	10b
+	eieio
+#endif /* CONFIG_SMP */
 	sync
 	tlbia
 	sync
 #ifdef __SMP__
 	tlbsync
 	sync
+	li	r0,0
+	stw	r0,0(r9)		/* clear hash_table_lock */
+	mtmsr	r10
+	SYNC
 #endif
 	blr	
 
@@ -138,11 +159,32 @@
  * Flush MMU TLB for a particular address
  */
 _GLOBAL(_tlbie)
+#if defined(CONFIG_SMP)
+	mfmsr	r10
+	sync
+	rlwinm	r0,r10,0,17,15		/* clear bit 16 (MSR_EE) */
+	mtmsr	r0
+	SYNC
+	lis	r9,hash_table_lock@h
+	ori	r9,r9,hash_table_lock@l
+	lwz	r8,PROCESSOR(r2)
+	oris	r8,r8,11
+10:	lwarx	r7,0,r9
+	cmpi	0,r7,0
+	bne-	10b
+	stwcx.	r8,0,r9
+	bne-	10b
+	eieio
+#endif /* CONFIG_SMP */
 	tlbie	r3
 	sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	tlbsync
 	sync
+	li	r0,0
+	stw	r0,0(r9)		/* clear hash_table_lock */
+	mtmsr	r10
+	SYNC
 #endif
 	blr
 
@@ -312,8 +354,10 @@
  * The *_ns versions don't do byte-swapping.
  */
 _GLOBAL(_insb)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,1
+	blelr-
 00:	lbz	r5,0(r3)
 	eieio
 	stbu	r5,1(r4)
@@ -321,8 +365,10 @@
 	blr
 
 _GLOBAL(_outsb)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,1
+	blelr-
 00:	lbzu	r5,1(r4)
 	stb	r5,0(r3)
 	eieio
@@ -330,8 +376,10 @@
 	blr	
 
 _GLOBAL(_insw)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,2
+	blelr-
 00:	lhbrx	r5,0,r3
 	eieio
 	sthu	r5,2(r4)
@@ -339,8 +387,10 @@
 	blr
 
 _GLOBAL(_outsw)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,2
+	blelr-
 00:	lhzu	r5,2(r4)
 	eieio
 	sthbrx	r5,0,r3	
@@ -348,8 +398,10 @@
 	blr	
 
 _GLOBAL(_insl)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,4
+	blelr-
 00:	lwbrx	r5,0,r3
 	eieio
 	stwu	r5,4(r4)
@@ -357,8 +409,10 @@
 	blr
 
 _GLOBAL(_outsl)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,4
+	blelr-
 00:	lwzu	r5,4(r4)
 	stwbrx	r5,0,r3
 	eieio
@@ -367,8 +421,10 @@
 
 _GLOBAL(ide_insw)
 _GLOBAL(_insw_ns)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,2
+	blelr-
 00:	lhz	r5,0(r3)
 	eieio
 	sthu	r5,2(r4)
@@ -377,8 +433,10 @@
 
 _GLOBAL(ide_outsw)
 _GLOBAL(_outsw_ns)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,2
+	blelr-
 00:	lhzu	r5,2(r4)
 	sth	r5,0(r3)
 	eieio
@@ -386,8 +444,10 @@
 	blr	
 
 _GLOBAL(_insl_ns)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,4
+	blelr-
 00:	lwz	r5,0(r3)
 	eieio
 	stwu	r5,4(r4)
@@ -395,8 +455,10 @@
 	blr
 
 _GLOBAL(_outsl_ns)
+	cmpwi	0,r5,0
 	mtctr	r5
 	subi	r4,r4,4
+	blelr-
 00:	lwzu	r5,4(r4)
 	stw	r5,0(r3)
 	eieio
@@ -494,15 +556,13 @@
 	mfspr	r3,HID0
 	blr
 
-_GLOBAL(_get_ICTC)
-	mfspr	r3,ICTC
-	blr
-
-_GLOBAL(_set_ICTC)
-	mtspr	ICTC,r3
+_GLOBAL(_set_HID0)
+	sync
+	mtspr	HID0, r3
+	sync
+	isync /* Handle erratas in some cases */
 	blr
 
-	
 /*
 	L2CR functions
 	Copyright Š 1997-1998 by PowerLogix R & D, Inc.
@@ -524,6 +584,17 @@
 /*
 	Thur, Dec. 12, 1998.
 	- First public release, contributed by PowerLogix.
+	***********
+	Sat, Aug. 7, 1999.
+	- Terry: Made sure code disabled interrupts before running. (Previously
+			it was assumed interrupts were already disabled).
+	- Terry: Updated for tentative G4 support.  4MB of memory is now flushed
+			instead of 2MB.  (Prob. only 3 is necessary).
+	- Terry: Updated for workaround to HID0[DPM] processor bug
+			during global invalidates.
+	***********
+	Thu, July 13, 2000.
+	- Terry: Added isync to correct for an errata.
 	
 	Author:	Terry Greeniaus (tgree@phys.ualberta.ca)
 	Please e-mail updates to this file to me, thanks!
@@ -562,82 +633,94 @@
 	causes cache pushes from the L1 cache to go to the L2 cache
 	instead of to main memory.
 */
-
+/*
+ * Summary: this procedure ignores the L2I bit in the value passed in,
+ * flushes the cache if it was already enabled, always invalidates the
+ * cache, then enables the cache if the L2E bit is set in the value
+ * passed in.
+ *   -- paulus.
+ */
 _GLOBAL(_set_L2CR)
-	/* Make sure this is a 750 chip */
+	/* Make sure this is a 750 or 7400 chip */
 	mfspr	r4,PVR
 	rlwinm	r4,r4,16,16,31
-	cmplwi	r4,0x0008
-	beq	thisIs750
-	cmplwi	r4,0x000c
-	beq thisIs750
-	li	r3,-1
-	blr
-	
-thisIs750:
-	/* Get the current enable bit of the L2CR into r4 */
-	mfspr	r4,L2CR
-	mfmsr	r7
-	
-	/* See if we want to perform a global inval this time. */
-	rlwinm	r6,r3,0,10,10	/* r6 contains the new invalidate bit */
-	rlwinm.	r5,r3,0,0,0	/* r5 contains the new enable bit */
-	rlwinm	r3,r3,0,11,9	/* Turn off the invalidate bit */
-	rlwimi	r3,r4,0,0,0	/* Keep the enable bit the same as it was. */
-	bne	dontDisableCache /* Only disable the cache if L2CRApply
-				    has the enable bit off */
-
-disableCache:
-	/* Disable the cache.  First, we turn off interrupts.
-	   An interrupt while we are flushing the cache could bring
-	   in data which may not get properly flushed. */
-	rlwinm	r4,r7,0,17,15	/* Turn off EE bit */
+	cmpwi	r4,0x0008
+	cmpwi	cr1,r4,0x000c
+	cror	2,2,4*cr1+2
+	bne	99f
+
+	/* Turn off interrupts and data relocation. */
+	mfmsr	r7		/* Save MSR in r7 */
+	rlwinm	r4,r7,0,17,15
+	rlwinm	r4,r4,0,28,26	/* Turn off DR bit */
 	sync
 	mtmsr	r4
 	sync
+
+	/* Get the current enable bit of the L2CR into r4 */
+	mfspr	r4,L2CR
 	
-/*
-	Now, read the first 2MB of memory to put new data in the cache.
-	(Actually we only need the size of the L2 cache plus the size
-	of the L1 cache, but 2MB will cover everything just to be safe).
-*/
-	lis	r4,0x0001
+	/* Tweak some bits */
+	rlwinm	r5,r3,0,0,0		/* r5 contains the new enable bit */
+	rlwinm	r3,r3,0,11,9		/* Turn off the invalidate bit */
+	rlwinm	r3,r3,0,1,31		/* Turn off the enable bit */
+
+	/* Check to see if we need to flush */
+	rlwinm.	r4,r4,0,0,0
+	beq	2f
+
+	/* Flush the cache. First, read the first 4MB of memory (physical) to
+	 * put new data in the cache.  (Actually we only need
+	 * the size of the L2 cache plus the size of the L1 cache, but 4MB will
+	 * cover everything just to be safe).
+	 */
+		
+	 /**** Might be a good idea to set L2DO here - to prevent instructions
+	       from getting into the cache.  But since we invalidate
+	       the next time we enable the cache it doesn't really matter.
+	  ****/
+
+	lis	r4,0x0002
 	mtctr	r4
-	lis	r4,KERNELBASE@h
-1:	lwzx	r0,r0,r4
-	addi	r4,r4,0x0020		/* Go to start of next cache line */
+	li	r4,0
+1:
+	lwzx	r0,r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
 	bdnz	1b
 	
-	/* Now, flush the first 2MB of memory */
-	lis	r4,0x0001
+	/* Now, flush the first 4MB of memory */
+	lis	r4,0x0002
 	mtctr	r4
-	lis	r4,KERNELBASE@h
+	li	r4,0
 	sync
-2:	dcbf	r0,r4
-	addi	r4,r4,0x0020	/* Go to start of next cache line */
-	bdnz	2b
-	
-	/* Turn off the L2CR enable bit. */
-	rlwinm	r3,r3,0,1,31
-	
-dontDisableCache:
-	/* Set up the L2CR configuration bits */
+1:
+	dcbf	r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+
+2:
+	/* Set up the L2CR configuration bits (and switch L2 off) */
 	sync
 	mtspr	L2CR,r3
 	sync
 
-	/* Reenable interrupts if necessary. */
-	mtmsr	r7
+	/* Before we perform the global invalidation, we must disable dynamic
+	 * power management via HID0[DPM] to work around a processor bug where
+	 * DPM can possibly interfere with the state machine in the processor
+	 * that invalidates the L2 cache tags.
+	 */
+	mfspr	r8,HID0			/* Save HID0 in r8 */
+	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
 	sync
-	
-	cmplwi	r6,0
-	beq	noInval
-	
+	mtspr	HID0,r4			/* Disable DPM */
+	sync
+
 	/* Perform a global invalidation */
 	oris	r3,r3,0x0020
 	sync
 	mtspr	L2CR,r3
 	sync
+	isync				/* For errata */
 
 	/* Wait for the invalidation to complete */
 3:	mfspr	r3,L2CR
@@ -649,27 +732,38 @@
 	mtspr	L2CR,r3
 	sync
 	
-noInval:
+	/* Restore HID0[DPM] to whatever it was before */
+	sync
+	mtspr	1008,r8
+	sync
+
 	/* See if we need to enable the cache */
 	cmplwi	r5,0
-	beqlr
+	beq	4f
 
 	/* Enable the cache */
 	oris	r3,r3,0x8000
 	mtspr	L2CR,r3
 	sync
+
+	/* Restore MSR (restores EE and DR bits to original state) */
+4:	sync
+	mtmsr	r7
+	sync
+	blr
+
+99:	li	r3,-1
 	blr
 
 _GLOBAL(_get_L2CR)
 	/* Make sure this is a 750 chip */
 	mfspr	r3,PVR
-	rlwinm	r3,r3,16,16,31
-	cmplwi	r3,0x0008
-	beq	1f
-	cmplwi	r3,0x000c
+	srwi	r3,r3,16
+	cmpwi	r3,0x0008
+	cmpwi	cr1,r3,0x000c
 	li	r3,0
+	cror	2,2,4*cr1+2
 	bnelr
-1:	
 	/* Return the L2CR contents */
 	mfspr	r3,L2CR
 	blr
@@ -677,16 +771,6 @@
 /* --- End of PowerLogix code ---
  */
 
-/*
-_GLOBAL(_get_L2CR)
-	mfspr	r3,L2CR
-	blr
-
-_GLOBAL(_set_L2CR)
-	mtspr	L2CR,r3
-	blr
-		
-*/
 
 /*
  * These are used in the alignment trap handler when emulating
@@ -944,11 +1028,7 @@
 	.long sys_getresuid	/* 165 */
 	.long sys_query_module
 	.long sys_poll
-#ifdef CONFIG_NFSD
 	.long sys_nfsservctl
-#else
-	.long sys_ni_syscall
-#endif		
 	.long sys_setresgid
 	.long sys_getresgid	/* 170 */
 	.long sys_prctl
@@ -970,4 +1050,16 @@
 	.long sys_ni_syscall		/* streams1 */
 	.long sys_ni_syscall		/* streams2 */
 	.long sys_vfork
-	.space (NR_syscalls-183)*4
+	.long sys_ni_syscall		/* 190 */	/* MacOnLinux - old */
+	.long sys_ni_syscall		/* 191 */	/* Unused */
+	.long sys_ni_syscall		/* 192 - reserved - mmap2 */
+	.long sys_ni_syscall		/* 193 - reserved - truncate64 */
+	.long sys_ni_syscall		/* 194 - reserved - ftruncate64 */
+	.long sys_ni_syscall		/* 195 - reserved - stat64 */
+	.long sys_ni_syscall		/* 196 - reserved - lstat64 */
+	.long sys_ni_syscall		/* 197 - reserved - fstat64 */
+	.long sys_pciconfig_read	/* 198 */
+	.long sys_pciconfig_write 	/* 199 */
+	.long sys_pciconfig_iobase 	/* 200 */
+	.long sys_ni_syscall		/* 201 - reserved - MacOnLinux - new */
+	.space (NR_syscalls-201)*4
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- linux-2.2.18-pre20/arch/ppc/kernel/open_pic.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/open_pic.c	Mon Dec  3 22:14:16 2001
@@ -1,48 +1,126 @@
+/*
+ * open_pic.c
+ *
+ * Common support routines for platforms with an OpenPIC interrupt controller
+ *
+ */
+
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/openpic.h>
 #include <asm/irq.h>
+#include <asm/processor.h>
 #include "open_pic.h"
 #include "i8259.h"
 
-#ifdef __SMP__
-void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	smp_message_recv(cpl-OPENPIC_VEC_IPI);
-}
-#endif /* __SMP__ */
+extern volatile unsigned char *chrp_int_ack_special;
 
-void chrp_mask_and_ack_irq(unsigned int irq_nr)
+void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
 {
-	if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
-		i8259_pic.mask_and_ack(irq_nr);
-}
+	int irq;
+        int openpic_eoi_done = 0;
 
-static void chrp_mask_irq(unsigned int irq_nr)
-{
-	if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
-		i8259_pic.disable(irq_nr);
+#ifdef __SMP__
+        {
+                unsigned int loops = 1000000;
+                while (test_bit(0, &global_irq_lock)) {
+                        if (smp_processor_id() == global_irq_holder) {
+                                printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                                break;
+                        }
+                        if (loops-- == 0) {
+                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                        }
+                }
+        }
+#endif /* __SMP__ */
+	
+        irq = openpic_irq(smp_processor_id());
+	/* make sure open_pic.irq_offset is set to something!
+	 * do we really need the _MACH_Pmac test??
+	 */
+        if (!(_machine == _MACH_Pmac) && (irq == open_pic.irq_offset))
+        {
+                /*
+                 * This magic address generates a PCI IACK cycle.
+                 *
+                 * This should go in the above mask/ack code soon. -- Cort
+                 */
+		if ( chrp_int_ack_special )
+			irq = *chrp_int_ack_special;
+#ifndef CONFIG_PMAC
+		else
+			irq = i8259_irq(0);
+#endif
+                /*
+                 * Acknowledge as soon as possible to allow i8259
+                 * interrupt nesting                         */
+                openpic_eoi(smp_processor_id());
+                openpic_eoi_done = 1;
+        }
+        if (irq == OPENPIC_VEC_SPURIOUS)
+        {
+                /*
+                 * Spurious interrupts should never be
+                 * acknowledged
+                 */
+                ppc_spurious_interrupts++;
+                openpic_eoi_done = 1;
+		goto out;
+        }
+
+        if (irq < 0)
+        {
+                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                ppc_spurious_interrupts++;
+        }
 	else
-		openpic_disable_irq(irq_nr-open_pic.irq_offset);
+        {
+		ppc_irq_dispatch_handler( regs, irq );
+	}
+out:
+        if (!openpic_eoi_done)
+                openpic_eoi(smp_processor_id());
 }
 
-static void chrp_unmask_irq(unsigned int irq_nr)
+#ifdef __SMP__
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
-	if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
-		i8259_pic.enable(irq_nr);
-	else
-		openpic_enable_irq(irq_nr-open_pic.irq_offset);
+	smp_message_recv(cpl-OPENPIC_VEC_IPI);
 }
+#endif /* __SMP__ */
+
 
 struct hw_interrupt_type open_pic = {
 	" OpenPIC  ",
 	NULL,
 	NULL,
 	NULL,
-	chrp_unmask_irq,
-	chrp_mask_irq,
-	chrp_mask_and_ack_irq,
+	openpic_enable_irq,
+	openpic_disable_irq,
+	/* Theorically, the mask&ack should be NULL for OpenPIC. However, doing
+	 * so shows tons of bogus interrupts coming in.
+	 * This problem is apparently due to the common code always calling
+	 * unmask(). I apparently (need more test) fixed it in the 2.4 new IRQ
+	 * management by cleanly implementing the handler's end() function, so
+	 * neither mask nor unmask are needed. In the meantime, the fix below will
+	 * work for 2.2 -Benh
+	 *
+	 * Hopefully this will fix my bogus interrups on MTX
+	 * I merged everthing together so we don't have the same code in three
+	 * places. This might cause stability problems, but I'd rather
+	 * get it right once than three different times because someone forgot
+	 * to make the same change to PReP or something --Troy
+	 */
+	openpic_disable_irq,
 	0
 };
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h
--- linux-2.2.18-pre20/arch/ppc/kernel/open_pic.h	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/open_pic.h	Mon Dec  3 22:14:16 2001
@@ -6,6 +6,7 @@
 
 extern struct hw_interrupt_type open_pic;
 
+void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
 void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
 void openpic_enable_IPI(u_int ipi);
 void do_openpic_setup_cpu(void);
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c
--- linux-2.2.18-pre20/arch/ppc/kernel/openpic.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/openpic.c	Mon Dec  3 22:14:16 2001
@@ -175,7 +175,10 @@
  * Note: We might want to adjust priorities too.
  */
 
-__initfunc(void openpic_init(int main_pic))
+/* Not an init func, called on pbook wakeup --BenH */
+void
+__init
+openpic_init(int main_pic)
 {
 	u_int t, i;
 	u_int timerfreq;
@@ -227,7 +230,7 @@
 	    
 		/* Initialize IPI interrupts */
 		for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-			openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i);
+			openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i);
 		}
 	    
 		if (_machine != _MACH_Pmac) {
@@ -264,7 +267,7 @@
     				    	openpic_initirq(	np->intrs[j].line,
     				    				pri,
     				    				np->intrs[j].line,
-    				    				np->intrs[j].sense,
+    				    				0,
     				    				np->intrs[j].sense);
     				    	irq_desc[np->intrs[j].line].level = np->intrs[j].sense;
     				    }
@@ -309,6 +312,10 @@
 {
 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
 			 OPENPIC_CONFIG_RESET);
+	/* Wait for reset to complete */
+	while(openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+    			OPENPIC_CONFIG_RESET))
+    		;
 }
 
 
@@ -459,12 +466,12 @@
 	
 	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
 		  openpic_enable_IPI(i);
-#if 0	
+
 	/* let the openpic know we want intrs */
 	for ( i = 0; i < NumSources ; i++ )
 		openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination)
 			       | (1<<smp_processor_id()) );
-#endif	
+
 	openpic_set_priority(smp_processor_id(), 0);
 }    
 
@@ -500,7 +507,11 @@
  */
 void openpic_enable_irq(u_int irq)
 {
-	check_arg_irq(irq);
+	/* on SMP, we get IPI vector numbers here, we should handle them
+	 * or at least ignore them.
+	 */
+	if (irq < 0 || irq >= NumSources)
+		return;
 	openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
@@ -509,15 +520,30 @@
 			OPENPIC_MASK));
 }
 
+u_int openpic_get_enable(u_int irq)
+{
+	if (irq < 0 || irq >= NumSources)
+		return 0;
+	return !openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+			OPENPIC_MASK);
+}
+
 void openpic_disable_irq(u_int irq)
 {
-	check_arg_irq(irq);
+	u32 vp;
+	
+	/* on SMP, we get IPI vector numbers here, we should handle them
+	 * or at least ignore them.
+	 */
+	if (irq < 0 || irq >= NumSources)
+		return;
 	openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
-		mb();
-	} while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
-    			OPENPIC_MASK));
+		mb();  /* sync is probably useless here */
+		vp = openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+    			OPENPIC_MASK | OPENPIC_ACTIVITY);
+	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
 }
 
 /*
@@ -564,3 +590,50 @@
 				OPENPIC_SENSE_LEVEL,
 				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
+
+#ifdef CONFIG_PMAC_PBOOK
+static u32 save_ipi_vp[OPENPIC_NUM_IPI];
+static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
+static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
+static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
+
+__pmac
+void
+openpic_sleep_save_intrs(void)
+{
+	int	i;
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
+	for (i=0; i<NumSources; i++) {
+		save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority);
+		save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
+	}
+	for (i=0; i<NumProcessors; i++) {
+		save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
+		openpic_set_priority(i, 0xf);
+	}
+}
+
+__pmac
+void
+openpic_sleep_restore_intrs(void)
+{
+	int	i;
+
+	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
+		openpic_maptimer(i, 0);
+	}
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
+	for (i=0; i<NumSources; i++) {
+		openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
+		openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
+	}
+	openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
+	openpic_disable_8259_pass_through();
+	for (i=0; i<NumProcessors; i++)
+		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
+}
+#endif /* CONFIG_PMAC_PBOOK */
\ No newline at end of file
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- linux-2.2.18-pre20/arch/ppc/kernel/pci.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/pci.c	Mon Dec  3 22:14:16 2001
@@ -10,15 +10,20 @@
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/openpic.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#include <asm/pci.h>
 #include <asm/residual.h>
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/gg2.h>
+#include <asm/uaccess.h>
 
 #include "pci.h"
 
@@ -105,3 +110,156 @@
 	}
 }
 #endif
+
+
+void *
+pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical)
+{
+	if (!ppc_md.pci_dev_io_base) {
+		/* Please, someone fix this for non-pmac machines, we
+		 * need either the virtual or physical PCI IO base
+		 */
+		return 0;
+	}
+	return ppc_md.pci_dev_io_base(bus, devfn, physical);
+}
+
+void *
+pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+	/* Default memory base is 0 (1:1 mapping) */
+	if (!ppc_md.pci_dev_mem_base) {
+		/* Please, someone fix this for non-pmac machines.*/
+		return 0;
+	}
+	return ppc_md.pci_dev_mem_base(bus, devfn);
+}
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int
+pci_dev_root_bridge(unsigned char bus, unsigned char devfn)
+{
+	/* Defaults to 0 */
+	if (!ppc_md.pci_dev_root_bridge)
+		return 0;
+	return ppc_md.pci_dev_root_bridge(bus, devfn);
+}
+
+/*
+ * Those syscalls are derived from the Alpha versions, they
+ * allow userland apps to retreive the per-device iobase and
+ * mem-base. They also provide wrapper for userland to do
+ * config space accesses.
+ * The "host_number" returns the number of the Uni-N sub bridge
+ */
+
+asmlinkage int
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+		   unsigned long off, unsigned long len,
+		   unsigned char *buf)
+{
+	unsigned char ubyte;
+	unsigned short ushort;
+	unsigned int uint;
+	long err = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!pcibios_present())
+		return -ENOSYS;
+	
+	switch (len) {
+	case 1:
+		err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
+		put_user(ubyte, buf);
+		break;
+	case 2:
+		err = pcibios_read_config_word(bus, dfn, off, &ushort);
+		put_user(ushort, (unsigned short *)buf);
+		break;
+	case 4:
+		err = pcibios_read_config_dword(bus, dfn, off, &uint);
+		put_user(uint, (unsigned int *)buf);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+asmlinkage int
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+		    unsigned long off, unsigned long len,
+		    unsigned char *buf)
+{
+	unsigned char ubyte;
+	unsigned short ushort;
+	unsigned int uint;
+	long err = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!pcibios_present())
+		return -ENOSYS;
+
+	switch (len) {
+	case 1:
+		err = get_user(ubyte, buf);
+		if (err)
+			break;
+		err = pcibios_write_config_byte(bus, dfn, off, ubyte);
+		if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	case 2:
+		err = get_user(ushort, (unsigned short *)buf);
+		if (err)
+			break;
+		err = pcibios_write_config_word(bus, dfn, off, ushort);
+		if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	case 4:
+		err = get_user(uint, (unsigned int *)buf);
+		if (err)
+			break;
+		err = pcibios_write_config_dword(bus, dfn, off, uint);
+		if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory.  Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+asmlinkage long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+	long result = -EOPNOTSUPP;
+	
+	switch (which) {
+	case IOBASE_BRIDGE_NUMBER:
+		return (long)pci_dev_root_bridge(bus, devfn);
+	case IOBASE_MEMORY:
+		return (long)pci_dev_mem_base(bus, devfn);
+	case IOBASE_IO:
+		result = (long)pci_dev_io_base(bus, devfn, 1);
+		if (result == 0)
+			result = -EOPNOTSUPP;
+		break;
+	}
+
+	return result;
+}
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- linux-2.2.18-pre20/arch/ppc/kernel/pmac_pci.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/pmac_pci.c	Mon Dec  3 22:14:16 2001
@@ -32,6 +32,8 @@
 	struct device_node*	node;
 	volatile unsigned int*	cfg_addr;
 	volatile unsigned int*	cfg_data;
+	void*			iobase;
+	void*			iobase_phys;
 };
 
 static struct uninorth_data uninorth_bridges[3];
@@ -83,6 +85,81 @@
 	return 0;
 }
 
+/* This routines figures out on which root bridge a given PCI device
+ * is attached.
+ * 
+ * WARNING: When passed the address of the bridge itself (11), it must
+ *          return the AGP bus. Currently, it returns 0, which is by
+ *          chance the AGP one. We may have to improve that however...
+ */
+__pmac
+int
+pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn)
+{
+	struct device_node *node, *bridge_node;
+	int bridge = uninorth_default;
+
+	if (uninorth_count == 0)
+		return 0;
+	if (bus == 0 && PCI_SLOT(dev_fn) < 11)
+		return 0;
+	
+	/* We look for the OF device corresponding to this bus/devfn pair. If we
+	 * don't find it, we default to the external PCI */
+	bridge_node = NULL;
+	node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
+	if (node) {
+	    /* note: we don't stop on the first occurence since we need to go
+             * up to the root bridge */
+	    do {
+		if (node->type && !strcmp(node->type, "pci") 
+			&& device_is_compatible(node, "uni-north"))
+			bridge_node = node;
+		node=node->parent;
+	    } while (node);
+	}
+	if (bridge_node) {
+	    int i;
+	    for (i=0;i<uninorth_count;i++)
+		if (uninorth_bridges[i].node == bridge_node) {
+		    bridge = i;
+		    break;
+		}
+	}
+
+	if (bridge == -1) {
+		printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+		return 0;
+	}
+
+	return bridge;	
+}
+
+__pmac
+void *
+pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical)
+{
+	int bridge = -1;
+	if (uninorth_count != 0)
+		bridge = pmac_pci_dev_root_bridge(bus, devfn);
+	if (bridge == -1) {
+		struct bridge_data *bp;
+
+		if (bus > max_bus || (bp = bridges[bus]) == 0)
+			return 0;
+		return physical ? bp->io_base_phys : bp->io_base;
+	}
+	return physical ? uninorth_bridges[bridge].iobase_phys
+		: uninorth_bridges[bridge].iobase;
+}
+
+__pmac
+void *
+pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+	return 0;
+}
+
 /* This function only works for bus 0, uni-N uses a different mecanism for
  * other busses (see below)
  */
@@ -99,48 +176,20 @@
 	|1UL)
 	
 
-/* We should really use RTAS here, unfortunately, it's not available with BootX.
- * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff
- * later, once I have something that works enough with BootX.
- */
 __pmac static
 unsigned int
 uni_north_access_data(unsigned char bus, unsigned char dev_fn,
 				unsigned char offset)
 {
-	struct device_node *node, *bridge_node;
-	int bridge = uninorth_default;
+	int bridge;
 	unsigned int caddr;
 
-	if (bus == 0) {
-		if (PCI_SLOT(dev_fn) < 11) {
-			return 0;
-		}
-		/* We look for the OF device corresponding to this bus/devfn pair. If we
-		 * don't find it, we default to the external PCI */
-		bridge_node = NULL;
-		node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
-		if (node) {
-                    /* note: we don't stop on the first occurence since we need to go
-                     * up to the root bridge */
-		    do {
-			if (!strcmp(node->type, "pci"))
-				bridge_node = node;
-			node=node->parent;
-		    } while (node);
-		}
-		if (bridge_node) {
-		    int i;
-		    for (i=0;i<uninorth_count;i++)
-			if (uninorth_bridges[i].node == bridge_node) {
-			    bridge = i;
-			    break;
-			}
-		}
+	bridge = pmac_pci_dev_root_bridge(bus, dev_fn);
+	if (bus == 0)
 		caddr = UNI_N_CFA0(dev_fn, offset);
-	} else
+	else
 		caddr = UNI_N_CFA1(bus, dev_fn, offset);
-
+	
 	if (bridge == -1) {
 		printk(KERN_WARNING "pmac_pci: no default bridge !\n");
 		return 0;
@@ -556,6 +605,50 @@
 	out_le32((volatile unsigned int *)bp->cfg_data, val);
 }
 
+static int __init
+fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+	for (; node != 0;node = node->sibling) {
+		int * bus_range;
+		unsigned int *class_code;			
+		int len;
+
+		/* For PCI<->PCI bridges or CardBus bridges, we go down */
+		class_code = (unsigned int *) get_property(node, "class-code", 0);
+		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+			continue;
+		bus_range = (int *) get_property(node, "bus-range", &len);
+		if (bus_range != NULL && len > 2 * sizeof(int)) {
+			if (bus_range[1] > higher)
+				higher = bus_range[1];
+		}
+		higher = fixup_one_level_bus_range(node->child, higher);
+	}
+	return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ * 
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init
+fixup_bus_range(struct device_node *bridge)
+{
+	int * bus_range;
+	int len;
+	
+	/* Lookup the "bus-range" property for the hose */		
+	bus_range = (int *) get_property(bridge, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get bus-range for %s\n",
+			       bridge->full_name);
+		return;
+	}
+	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
 
 __initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end))
 {
@@ -596,6 +689,7 @@
 			       dev->full_name);
 			continue;
 		}
+		fixup_bus_range(dev);
 		bus_range = (int *) get_property(dev, "bus-range", &len);
 		if (bus_range == NULL || len < 2 * sizeof(int)) {
 			printk(KERN_WARNING "Can't get bus-range for %s\n",
@@ -613,6 +707,9 @@
 			uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
 			uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
 			uninorth_bridges[i].node = dev;
+			uninorth_bridges[i].iobase_phys = (void *)addr->address;
+			/* is 0x10000 enough for io space ? */
+			uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000);
 			/* XXX This is the bridge with the PCI expansion bus. This is also the
 			 * address of the bus that will receive type 1 config accesses and io
 			 * accesses. Appears to be correct for iMac DV and G4 Sawtooth too.
@@ -630,8 +727,8 @@
 		if (device_is_compatible(dev, "uni-north")) {
 			bp->cfg_addr = 0;
 			bp->cfg_data = 0;
-			/* is 0x10000 enough for io space ? */
-			bp->io_base = (void *)ioremap(addr->address, 0x10000);
+			bp->io_base = uninorth_bridges[uninorth_count-1].iobase;
+			bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys;
 		} else if (strcmp(dev->name, "pci") == 0) {
 			/* XXX assume this is a mpc106 (grackle) */
 			bp->cfg_addr = (volatile unsigned int *)
@@ -639,6 +736,7 @@
 			bp->cfg_data = (volatile unsigned char *)
 				ioremap(0xfee00000, 0x1000);
                         bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
+                        bp->io_base_phys = (void *)0xfe000000;
                         if (machine_is_compatible("AAPL,PowerBook1998"))
                         	grackle_set_loop_snoop(bp, 1);
 #if 0 			/* Disabled for now, HW problems ??? */
@@ -651,6 +749,7 @@
 			bp->cfg_data = (volatile unsigned char *)
 				ioremap(addr->address + 0xc00000, 0x1000);
 			bp->io_base = (void *) ioremap(addr->address, 0x10000);
+			bp->io_base_phys = (void *)addr->address;
 		}
 		if (isa_io_base == 0)
 			isa_io_base = (unsigned long) bp->io_base;
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- linux-2.2.18-pre20/arch/ppc/kernel/pmac_pic.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/pmac_pic.c	Mon Dec  3 22:14:16 2001
@@ -10,6 +10,7 @@
 #include <asm/smp.h>
 #include <asm/prom.h>
 #include "pmac_pic.h"
+#include "open_pic.h"
 
 struct pmac_irq_hw {
         unsigned int    flag;
@@ -28,7 +29,8 @@
 
 static int max_irqs;
 static int max_real_irqs;
-static int has_openpic = 0;
+
+extern u_int openpic_read(volatile u_int *addr);
 
 #define MAXCOUNT 10000000
 
@@ -106,18 +108,6 @@
         pmac_set_irq_mask(irq_nr);
 }
 
-static void pmac_openpic_mask_irq(unsigned int irq_nr)
-{
-	openpic_disable_irq(irq_nr);
-}
-
-static void pmac_openpic_unmask_irq(unsigned int irq_nr)
-{
-	openpic_enable_irq(irq_nr);
-}
-
-
-
 struct hw_interrupt_type pmac_pic = {
         " PMAC-PIC ",
         NULL,
@@ -140,17 +130,6 @@
 	0
 };
 
-struct hw_interrupt_type pmac_open_pic = {
-	" OpenPIC  ",
-	NULL,
-	NULL,
-	NULL,
-	pmac_openpic_unmask_irq,
-	pmac_openpic_mask_irq,
-	NULL,/*pmac_openpic_mask_irq,*/
-	0
-};
-
 static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
 {
 	int irq, bits;
@@ -179,6 +158,8 @@
 	    int            cpu,
             int            isfake)
 {
+	extern void psurge_smp_message_recv(void);
+
 	int irq;
 	unsigned long bits = 0;
 
@@ -193,7 +174,7 @@
                         if (xmon_2nd)
                                 xmon(regs);
 #endif
-                        pmac_smp_message_recv();
+                        psurge_smp_message_recv();
                         goto out;
                 }
                 /* could be here due to a do_fake_interrupt call but we don't
@@ -221,29 +202,6 @@
         }
 #endif /* __SMP__ */
 
-	/* Yeah, I know, this could be a separate do_IRQ function */
-	if (has_openpic) {
-	    irq = openpic_irq(0);
-	    if (irq == OPENPIC_VEC_SPURIOUS) {
-                /* Spurious interrupts should never be ack'ed */
-                ppc_spurious_interrupts++;
-            } else {
-            	/* Can this happen ? (comes from CHRP code) */
-		if (irq < 0) {
-		    printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-                       irq, regs->nip);
-		    ppc_spurious_interrupts++;
-		} else {
-		    if (!irq_desc[irq].level)
-	                openpic_eoi(0);
-		    ppc_irq_dispatch_handler( regs, irq );
-		    if (irq_desc[irq].level)
-	                openpic_eoi(0);
-		}
-            }
-            return;
-	}
-
         for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
                 int i = irq >> 5;
                 bits = ld_le32(&pmac_irq_hw[i]->flag)
@@ -398,6 +356,8 @@
         struct device_node *irqctrler;
         volatile struct pmac_irq_hw *addr;
 	int second_irq;
+	u_int t;
+	int nr_irq;
 
 	/* We first try to detect Apple's new Core99 chipset, since mac-io
 	 * is quite different on those machines and contains an IBM MPIC2.
@@ -412,18 +372,38 @@
 		OpenPIC = (volatile struct OpenPIC *)
 			ioremap(irqctrler->addrs[0].address,
 			irqctrler->addrs[0].size);
-		for ( i = 0 ; i < NR_IRQS ; i++ ) {
-		    irq_desc[i].ctl = &pmac_open_pic;
+		/* from openpic.c code... --Troy
+		 * dynamically figure out how many interrupts 
+		 * We should really do something like panic
+		 * if nr_irq >= OPENPIC_VEC_IPI
+		 */
+		t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+                nr_irq = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+                                OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+		
+		for ( i = 0 ; i < nr_irq ; i++ ) {
+		    irq_desc[i].ctl = &open_pic;
 		    irq_desc[i].level = 0;
 		}
+		ppc_md.do_IRQ = open_pic_do_IRQ;
+		open_pic.irq_offset = 0;
 		openpic_init(1);
-		has_openpic = 1;
 #ifdef CONFIG_XMON
 		pswitch = find_devices("programmer-switch");
 		if (pswitch && pswitch->n_intrs)
 			request_irq(pswitch->intrs[0].line, xmon_irq, 0,	
 				"NMI - XMON", 0);
 #endif	/* CONFIG_XMON */
+#ifdef __SMP__
+		request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
+			    0, "IPI0", 0);
+		request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+			    0, "IPI1 (invalidate TLB)", 0);
+		request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+			    0, "IPI2 (stop CPU)", 0);
+		request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+			    0, "IPI3 (reschedule)", 0);
+#endif	/* __SMP__ */
 		return;
 	    }
 	    irqctrler = NULL;
@@ -507,17 +487,20 @@
  * sleep_save_intrs() saves the states of all interrupt enables
  * and disables all interupts except for the nominated one.
  * sleep_restore_intrs() restores the states of all interrupt enables.
+ * 
+ * TODO: Those should be sleep notifiers with high priority.
  */
 unsigned int sleep_save_mask[2];
 
 void
-sleep_save_intrs(int viaint)
+pmac_sleep_save_intrs(int viaint)
 {
 	sleep_save_mask[0] = ppc_cached_irq_mask[0];
 	sleep_save_mask[1] = ppc_cached_irq_mask[1];
 	ppc_cached_irq_mask[0] = 0;
 	ppc_cached_irq_mask[1] = 0;
-	set_bit(viaint, ppc_cached_irq_mask);
+	if (viaint > 0)
+		set_bit(viaint, ppc_cached_irq_mask);
 	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
@@ -526,9 +509,10 @@
 }
 
 void
-sleep_restore_intrs(void)
+pmac_sleep_restore_intrs(void)
 {
 	int i;
+
 
 	out_le32(&pmac_irq_hw[0]->enable, 0);
 	if (max_real_irqs > 32)
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 22:14:16 2001
@@ -57,19 +57,20 @@
 #include <asm/feature.h>
 #include <asm/ide.h>
 #include <asm/machdep.h>
-
+#include <asm/keyboard.h>
 #include <asm/time.h>
+
 #include "local_irq.h"
 #include "pmac_pic.h"
 
 #undef SHOW_GATWICK_IRQS
 
-void pmac_time_init(void);
-unsigned long pmac_get_rtc_time(void);
-int pmac_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void pmac_calibrate_decr(void);
-void pmac_setup_pci_ptrs(void);
+extern long pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_setup_pci_ptrs(void);
 
 extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int mackbd_getkeycode(unsigned int scancode);
@@ -79,22 +80,29 @@
 extern void mackbd_leds(unsigned char leds);
 extern void mackbd_init_hw(void);
 #ifdef CONFIG_MAGIC_SYSRQ
-unsigned char mackbd_sysrq_xlate[128];
+extern unsigned char mackbd_sysrq_xlate[128];
+extern unsigned char mac_hid_kbd_sysrq_xlate[128];
+extern unsigned char pckbd_sysrq_xlate[128];
 #endif /* CONFIG_MAGIC_SYSRQ */
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
+extern int keyboard_sends_linux_keycodes;
+extern int mac_hid_kbd_translate(unsigned char scancode,
+				 unsigned char *keycode, char raw_mode);
+extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
+extern void mac_hid_init_hw(void);
+
 extern void pmac_nvram_update(void);
 
+extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn);
+extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn);
+extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
+
 unsigned char drive_info;
 
 int ppc_override_l2cr = 0;
 int ppc_override_l2cr_value;
 
+static int current_root_goodness = -1;
+
 extern char saved_command_line[];
 
 extern int pmac_newworld;
@@ -104,7 +112,26 @@
 extern void zs_kgdb_hook(int tty_num);
 static void ohare_init(void);
 static void init_p2pbridge(void);
-static void init_uninorth(void);
+
+#ifdef CONFIG_SMP
+volatile static long int core99_l2_cache;
+void core99_init_l2(void)
+{
+ 	int cpu = smp_processor_id();
+ 
+	if ( (_get_PVR() >> 16) != 8 && (_get_PVR() >> 16) != 12 )
+		return;
+
+ 	if (cpu == 0){
+ 		core99_l2_cache = _get_L2CR();
+ 		printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+ 	} else {
+ 		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+ 		_set_L2CR(core99_l2_cache);
+ 		printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+ 	}
+}
+#endif /* CONFIG_SMP */
 
 __pmac
 int
@@ -247,7 +274,7 @@
 	struct device_node *cpu;
 	int *fp;
 
-	/* Set loops_per_sec to a half-way reasonable value,
+	/* Set loops_per_jiffy to a half-way reasonable value,
 	   for use until calibrate_delay gets called. */
 	cpu = find_type_devices("cpu");
 	if (cpu != 0) {
@@ -260,13 +287,13 @@
 			case 10:	/* mach V (604ev5) */
 			case 12:	/* G4 */
 			case 20:	/* 620 */
-				loops_per_jiffy = (*fp)/HZ;
+				loops_per_jiffy = *fp / HZ;
 				break;
 			default:	/* 601, 603, etc. */
-				loops_per_jiffy = (*fp / 2)/HZ;
+				loops_per_jiffy = *fp / (2*HZ);
 			}
 		} else
-			loops_per_jiffy = 50000000/HZ;
+			loops_per_jiffy = 50000000 / HZ;
 	}
 
 	/* this area has the CPU identification register
@@ -277,9 +304,10 @@
 
 	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
 	init_p2pbridge();
-	init_uninorth();
 	
-	/* Checks "l2cr-value" property in the registry */
+	/* Checks "l2cr-value" property in the registry
+	 * And enable G3/G4 Dynamic Power Management
+	 */
 	if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
 		struct device_node *np = find_devices("cpus");		
 		if (np == 0)
@@ -291,9 +319,11 @@
 				ppc_override_l2cr = 1;
 				ppc_override_l2cr_value = *l2cr;
 				_set_L2CR(0);
-				_set_L2CR(ppc_override_l2cr_value);
+				if (ppc_override_l2cr_value)
+					_set_L2CR(ppc_override_l2cr_value);
 			}
 		}
+		_set_HID0(_get_HID0() | HID0_DPM);
 	}
 
 	if (ppc_override_l2cr)
@@ -302,6 +332,10 @@
 				? "enabled" : "disabled");
 	feature_init();
 
+#ifdef CONFIG_SMP
+	core99_init_l2();
+#endif
+
 #ifdef CONFIG_KGDB
 	zs_kgdb_hook(0);
 #endif
@@ -368,38 +402,6 @@
 	}
 }
 
-__initfunc(static void init_uninorth(void))
-{
-	/* 
-	 * Turns OFF the gmac clock. The gmac driver will turn
-	 * it back ON when the interface is enabled. This save
-	 * power on portables.
-	 * 
-	 * Note: We could also try to turn OFF the PHY. Since this
-	 * has to be done by both the gmac driver and this code,
-	 * I'll probably end-up moving some of this out of the
-	 * modular gmac driver into a non-modular stub containing
-	 * some basic PHY management and power management stuffs
-	 */
-	struct device_node* uni_n = find_devices("uni-n");
-	struct device_node* gmac = find_devices("ethernet");
-	unsigned long* addr;
-	
-	if (!uni_n || uni_n->n_addrs < 1)
-		return;
-	addr = ioremap(uni_n->addrs[0].address, 0x300);
-
-	while(gmac) {
-		if (device_is_compatible(gmac, "gmac"))
-			break;
-		gmac = gmac->next;
-	}
-	if (gmac) {
-		*(addr + 8) &= ~0x00000002UL;
-		eieio();
-	}
-}
-
 extern char *bootpath;
 extern char *bootdevice;
 void *boot_host;
@@ -481,13 +483,14 @@
 
 /* can't be initfunc - can be called whenever a disk is first accessed */
 __pmac
-void note_bootable_part(kdev_t dev, int part)
+void note_bootable_part(kdev_t dev, int part, int goodness)
 {
 	static int found_boot = 0;
 	char *p;
 
 	/* Do nothing if the root has been set already. */
-	if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
+	if ((goodness < current_root_goodness) &&
+		(ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)))
 		return;
 	p = strstr(saved_command_line, "root=");
 	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
@@ -500,7 +503,7 @@
 	if (boot_dev == 0 || dev == boot_dev) {
 		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
 		boot_dev = NODEV;
-		printk(" (root on %d)", part);
+		current_root_goodness = goodness;
 	}
 }
 
@@ -655,7 +658,8 @@
 	ppc_md.get_rtc_time   = pmac_get_rtc_time;
 	ppc_md.calibrate_decr = pmac_calibrate_decr;
 
-#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
+#ifdef CONFIG_VT
+#ifdef CONFIG_MAC_KEYBOARD
 	ppc_md.kbd_setkeycode    = mackbd_setkeycode;
 	ppc_md.kbd_getkeycode    = mackbd_getkeycode;
 	ppc_md.kbd_translate     = mackbd_translate;
@@ -663,10 +667,30 @@
 	ppc_md.kbd_leds          = mackbd_leds;
 	ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
-	ppc_md.SYSRQ_KEY	 = 0x69;
+	ppc_md.sysrq_xlate	 = mackbd_sysrq_xlate;
+	SYSRQ_KEY		 = 0x69;
 #endif
+#elif defined(CONFIG_INPUT_ADBHID)
+	ppc_md.kbd_setkeycode    = 0;
+	ppc_md.kbd_getkeycode    = 0;
+	ppc_md.kbd_translate     = mac_hid_kbd_translate;
+	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
+	ppc_md.kbd_leds          = 0;
+	ppc_md.kbd_init_hw       = mac_hid_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_MAC_ADBKEYCODES
+	if (!keyboard_sends_linux_keycodes) {
+		ppc_md.sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+		SYSRQ_KEY = 0x69;
+	} else
+#endif /* CONFIG_MAC_ADBKEYCODES */
+	{
+		ppc_md.sysrq_xlate = pckbd_sysrq_xlate;
+		SYSRQ_KEY = 0x54;
+	}
 #endif
+#endif /* CONFIG_MAC_KEYBOARD */
+#endif /* CONFIG_VT */
 
 #if defined(CONFIG_BLK_DEV_IDE_PMAC)
         ppc_ide_md.insw = pmac_ide_insw;
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- linux-2.2.18-pre20/arch/ppc/kernel/pmac_support.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/pmac_support.c	Mon Dec  3 22:14:16 2001
@@ -24,6 +24,7 @@
 #include <asm/pmu.h>
 #include <asm/machdep.h>
 #include <asm/nvram.h>
+#include <asm/backlight.h>
 
 #undef DEBUG
 
@@ -66,6 +67,12 @@
 static int core99_bank = 0;
 static int nvram_partitions[3];
 
+static struct backlight_controller *backlighter = NULL;
+static void* backlighter_data = NULL;
+static int backlight_autosave = 0;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+
 /* FIXME: kmalloc fails to allocate the image now that I had to move it
  *        before time_init(). For now, I allocate a static buffer here
  *        but it's a waste of space on all but core99 machines
@@ -73,12 +80,12 @@
 #if 0
 static char* nvram_image;
 #else
-__pmac static char nvram_image[NVRAM_SIZE];
+static char nvram_image[NVRAM_SIZE];
 #endif
 
 extern int pmac_newworld;
 
-static u8
+static u8 __pmac
 chrp_checksum(struct chrp_header* hdr)
 {
 	u8 *ptr;
@@ -90,7 +97,7 @@
 	return sum;
 }
 
-static u32
+static u32 __pmac
 core99_calc_adler(u8 *buffer)
 {
 	int cnt;
@@ -113,7 +120,7 @@
 	return (high << 16) | low;
 }
 
-static u32
+static u32 __pmac
 core99_check(u8* datas)
 {
 	struct core99_header* hdr99 = (struct core99_header*)datas;
@@ -139,7 +146,7 @@
 	return hdr99->generation;
 }
 
-static int
+static int __pmac
 core99_erase_bank(int bank)
 {
 	int stat, i;
@@ -163,7 +170,7 @@
 	return 0;
 }
 
-static int
+static int __pmac
 core99_write_bank(int bank, u8* datas)
 {
 	int i, stat = 0;
@@ -191,7 +198,7 @@
 	return 0;	
 }
 
-static void
+static void __pmac
 lookup_partitions(void)
 {
 	u8 buffer[17];
@@ -281,7 +288,8 @@
 	} else if (nvram_naddrs == 2) {
 		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-	} else if (nvram_naddrs == 0 && adb_controller->kind == ADB_VIAPMU) {
+	} else if (nvram_naddrs == 0 && adb_controller &&
+		adb_controller->kind == ADB_VIAPMU) {
 		nvram_naddrs = -1;
 	} else {
 		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
@@ -290,7 +298,7 @@
 	lookup_partitions();
 }
 
-void
+void __pmac
 pmac_nvram_update(void)
 {
 	struct core99_header* hdr99;
@@ -317,7 +325,7 @@
 		printk("nvram: Error writing bank %d\n", core99_bank);
 }
 
-unsigned char
+unsigned char __pmac
 nvram_read_byte(int addr)
 {
 	struct adb_request req;
@@ -342,7 +350,7 @@
 	return 0;
 }
 
-void
+void __pmac
 nvram_write_byte(unsigned char val, int addr)
 {
 	struct adb_request req;
@@ -373,13 +381,13 @@
 	eieio();
 }
 
-int
+int __pmac
 pmac_get_partition(int partition)
 {
 	return nvram_partitions[partition];
 }
 
-u8
+u8 __pmac
 pmac_xpram_read(int xpaddr)
 {
 	int offset = nvram_partitions[pmac_nvram_XPRAM];
@@ -390,7 +398,7 @@
 	return nvram_read_byte(xpaddr + offset);
 }
 
-void
+void __pmac
 pmac_xpram_write(int xpaddr, u8 data)
 {
 	int offset = nvram_partitions[pmac_nvram_XPRAM];
@@ -399,5 +407,120 @@
 		return;
 		
 	nvram_write_byte(xpaddr + offset, data);
+}
+
+void __pmac
+register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
+{
+	struct device_node* bk_node;
+	char *prop;
+	int valid = 0;
+
+	bk_node = find_devices("backlight");
+	
+	/* Special case for the old PowerBooks, they don't yet have
+	 * the property we expect
+	 */
+	backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+		|| machine_is_compatible("AAPL,3500");
+	if ((backlight_autosave
+		|| machine_is_compatible("AAPL,PowerBook1998")
+		|| machine_is_compatible("PowerBook1,1"))
+		&& !strcmp(type, "pmu"))
+		valid = 1;
+	else if (bk_node) {
+		prop = get_property(bk_node, "backlight-control", NULL);
+		if (prop && !strncmp(prop, type, strlen(type)))
+			valid = 1;
+	}
+	if (!valid)
+		return;
+	backlighter = ctrler;
+	backlighter_data = data;
+	
+	if (bk_node && !backlight_autosave)
+		prop = get_property(bk_node, "bklt", NULL);
+	else
+		prop = NULL;
+	if (prop) {
+		backlight_level = ((*prop)+1) >> 1;
+		if (backlight_level > BACKLIGHT_MAX)
+			backlight_level = BACKLIGHT_MAX;
+	}
+	
+	if (backlight_autosave) {
+		struct adb_request req;
+		pmu_request(&req, NULL, 2, 0xd9, 0);
+		while (!req.complete)
+			pmu_poll();
+		backlight_level = req.reply[1] >> 4;
+	}
+
+	if (!backlighter->set_enable(1, backlight_level, data))
+		backlight_enabled = 1;
+
+	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
+		type, backlight_level);
+}
+
+void __pmac
+unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
+{
+	/* We keep the current backlight level (for now) */
+	if (ctrler == backlighter && data == backlighter_data)
+		backlighter = NULL;
+}
+
+int __pmac
+set_backlight_enable(int enable)
+{
+	int rc;
+	
+	if (!backlighter)
+		return -ENODEV;
+	rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
+	if (!rc)
+		backlight_enabled = enable;
+	return rc;
+}
+
+int __pmac
+get_backlight_enable(void)
+{
+	if (!backlighter)
+		return -ENODEV;
+	return backlight_enabled;
+}
+
+int __pmac
+set_backlight_level(int level)
+{
+	int rc = 0;
+	
+	if (!backlighter)
+		return -ENODEV;
+	if (level < BACKLIGHT_MIN)
+		level = BACKLIGHT_OFF;
+	if (level > BACKLIGHT_MAX)
+		level = BACKLIGHT_MAX;
+	if (backlight_enabled)
+		rc = backlighter->set_level(level, backlighter_data);
+	if (!rc)
+		backlight_level = level;
+	if (!rc && !backlight_autosave) {
+		level <<=1;
+		if (level & 0x10)
+			level |= 0x01;
+		// -- todo: save to property "bklt"
+	}
+	return rc;
+}
+
+int __pmac
+get_backlight_level(void)
+{
+	if (!backlighter)
+		return -ENODEV;
+	return backlight_level;
 }
 
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- linux-2.2.18-pre20/arch/ppc/kernel/pmac_time.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/pmac_time.c	Mon Dec  3 22:14:16 2001
@@ -53,7 +53,7 @@
 extern struct timezone sys_tz;
 
 __init
-void pmac_time_init(void)
+long pmac_time_init(void)
 {
 	s32 delta = 0;
 	int dst;
@@ -66,16 +66,13 @@
 	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
 	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
 		dst ? "on" : "off");
-	sys_tz.tz_minuteswest = -delta/60;
-	/* I _suppose_ this is 0:off, 1:on */
-	sys_tz.tz_dsttime = dst;
+	return -delta;
 }
 
 __pmac
 unsigned long pmac_get_rtc_time(void)
 {
 	struct adb_request req;
-	int offset = sys_tz.tz_minuteswest * 60;
 
 	/* Get the time from the RTC */
 	if (adb_controller == 0)
@@ -92,7 +89,7 @@
 			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
 			       req.reply_len);
 		return (req.reply[3] << 24) + (req.reply[4] << 16)
-			+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET + offset;
+			+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
 	case ADB_VIAPMU:
 		if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) {
 			printk("pmac_read_rtc_time: pmu_request failed\n");
@@ -104,7 +101,7 @@
 			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
 			       req.reply_len);
 		return (req.reply[1] << 24) + (req.reply[2] << 16)
-			+ (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET + offset;
+			+ (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
 	default:
 		return 0;
 	}
@@ -115,7 +112,7 @@
 	struct adb_request req;
 	int dst, delta;
 
-	nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60;
+	nowtime += RTC_OFFSET;
 
 	/* Set the time in the RTC */
 	if (adb_controller == 0)
@@ -146,15 +143,6 @@
 	default:
 		return 0;
 	}
-
-	/* write the timezone offset back into the xpram */
-	delta = sys_tz.tz_minuteswest * -60;
-	pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0x9, delta >> 16);
-	pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xa, delta >> 8);
-	pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xb, delta);
-	dst = pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 8);
-	dst = sys_tz.tz_dsttime? (dst | 0x80): (dst & ~0x80);
-	pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 8, dst);
 
 	return 1;
 }
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- linux-2.2.18-pre20/arch/ppc/kernel/ppc_htab.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/ppc_htab.c	Mon Dec  3 22:14:16 2001
@@ -587,9 +587,8 @@
 			buffer += len;
 			left -= len;
 			_set_L2CR(0);
-			_set_L2CR(val);
-			while ( _get_L2CR() & 0x1 )
-				/* wait for invalidate to finish */;
+			if (val)
+				_set_L2CR(val);
 			  
 		} else {
 			p = buf;
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.2.18-pre20/arch/ppc/kernel/ppc_ksyms.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Mon Dec  3 22:14:16 2001
@@ -81,8 +81,10 @@
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
+#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
 EXPORT_SYMBOL(_prep_type);
 EXPORT_SYMBOL(ucSystemType);
+#endif
 
 EXPORT_SYMBOL(atomic_add);
 EXPORT_SYMBOL(atomic_sub);
@@ -188,23 +190,13 @@
 EXPORT_SYMBOL(_read_unlock);
 EXPORT_SYMBOL(_write_lock);
 EXPORT_SYMBOL(_write_unlock);
-#endif
+#endif /* __SMP__ */
 
 EXPORT_SYMBOL(_machine);
 EXPORT_SYMBOL(ppc_md);
-
-EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_register);
-EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_poll);
-EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_poll);
-#ifdef CONFIG_PMAC_PBOOK
-EXPORT_SYMBOL(pmu_register_sleep_notifier);
-EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
-EXPORT_SYMBOL(pmu_enable_irled);
-#endif CONFIG_PMAC_PBOOK
 EXPORT_SYMBOL(abort);
+
+#ifndef CONFIG_MBX
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
 EXPORT_SYMBOL(find_compatible_devices);
@@ -215,25 +207,43 @@
 EXPORT_SYMBOL(find_pci_device_OFnode);
 EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
+#endif /* CONFIG_MBX */
+#ifdef CONFIG_POWERMAC
+EXPORT_SYMBOL(adb_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_poll);
+EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_poll);
+#endif /* CONFIG_POWERMAC */
+#ifdef CONFIG_PMAC_PBOOK
+EXPORT_SYMBOL(pmu_register_sleep_notifier);
+EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
+EXPORT_SYMBOL(pmu_enable_irled);
+#endif /* CONFIG_PMAC_PBOOK */
+#ifdef CONFIG_POWERMAC
 EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_dev_io_base);
+EXPORT_SYMBOL(pci_dev_mem_base);
 EXPORT_SYMBOL(pci_device_loc);
 EXPORT_SYMBOL(feature_set);
 EXPORT_SYMBOL(feature_clear);
 EXPORT_SYMBOL(feature_test);
-#ifdef CONFIG_SCSI
-EXPORT_SYMBOL(note_scsi_host);
-#endif
-EXPORT_SYMBOL(kd_mksound);
-/*#ifdef CONFIG_PMAC */
+EXPORT_SYMBOL(feature_set_gmac_power);
+EXPORT_SYMBOL(feature_set_gmac_phy_reset);
+EXPORT_SYMBOL(feature_set_usb_power);
+EXPORT_SYMBOL(feature_set_firewire_power);
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
 EXPORT_SYMBOL(pmac_xpram_read);
 EXPORT_SYMBOL(pmac_xpram_write);
-/*#endif*/ /* CONFIG_PMAC */
-#ifdef CONFIG_PPC_RTC
+#ifdef CONFIG_SCSI
+EXPORT_SYMBOL(note_scsi_host);
+#endif /* CONFIG_SCSI */
+#endif /* CONFIG_POWERMAC */
+EXPORT_SYMBOL(kd_mksound);
 EXPORT_SYMBOL(mktime);
 EXPORT_SYMBOL(to_tm);
-#endif
 
 EXPORT_SYMBOL(abs);
 
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- linux-2.2.18-pre20/arch/ppc/kernel/prep_pci.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/prep_pci.c	Mon Dec  3 22:14:16 2001
@@ -25,6 +25,7 @@
 #include <asm/machdep.h>
 
 #include "pci.h"
+#include "open_pic.h"
 
 #define MAX_DEVNR 22
 
@@ -42,8 +43,6 @@
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
 
-extern void chrp_do_IRQ(struct pt_regs *,int , int);
-
 /* Tables for known hardware */   
 
 /* Motorola PowerStackII - Utah */
@@ -784,7 +783,7 @@
 	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
 	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
 
-	ppc_md.do_IRQ = chrp_do_IRQ;
+	ppc_md.do_IRQ = open_pic_do_IRQ;
 	
 	/* If raven is present on Motorola store the system config register
 	 * for later use.
@@ -1131,7 +1130,7 @@
        if (n & 0xF0) {
                return (n & 0x0F);
        } else {
-               return(openpic_to_irq(n));
+               return(n+open_pic.irq_offset);
        }
 }
 
@@ -1168,6 +1167,17 @@
 			short_reg = 0x0000;
 			pcibios_write_config_word(dev->bus->number, 
 					dev->devfn, 0x44, short_reg);
+		}
+	}
+	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
+		if (OpenPIC){
+			/* Disable LEGIRQ mode so PCI INTs are routed to
+			   the 8259 */
+			pci_write_config_dword(dev, 0x40, 0x10ff00a1);
+		} else {
+			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
+			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
 		}
 	}
 }
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/prep_setup.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Dec  3 22:14:16 2001
@@ -47,9 +47,10 @@
 #include <asm/mk48t59.h>
 #include <asm/prep_nvram.h>
 #include <asm/raven.h>
-
-
+#include <asm/keyboard.h>
 #include <asm/time.h>
+#include <asm/vga.h>
+
 #include "local_irq.h"
 #include "i8259.h"
 #include "open_pic.h"
@@ -107,9 +108,6 @@
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;	/* starting block # of image */
 #endif
-#ifdef CONFIG_VGA_CONSOLE
-unsigned long vgacon_remap_base;
-#endif
 
 __prep
 int
@@ -617,8 +615,14 @@
                 irq_desc[i].ctl = &i8259_pic;
         i8259_init();
 #ifdef __SMP__
-	request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+	request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
 		    0, "IPI0", 0);
+	request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+		    0, "IPI1 (invalidate TLB)", 0);
+	request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+		    0, "IPI2 (stop CPU)", 0);
+	request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+		    0, "IPI3 (reschedule)", 0);
 #endif /* __SMP__ */
 }
 
@@ -857,8 +861,8 @@
 	ppc_md.kbd_leds          = pckbd_leds;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
-	ppc_md.SYSRQ_KEY	 = 0x54;
+	ppc_md.sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY		 = 0x54;
 #endif
 #endif
 }
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- linux-2.2.18-pre20/arch/ppc/kernel/process.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/process.c	Mon Dec  3 22:14:16 2001
@@ -233,7 +233,7 @@
 	printk("[");
 	for (; bits->bit != 0; ++bits) {
 		if (val & bits->bit) {
-			printk("%s", bits->name);
+			printk("%s%s", sep, bits->name);
 			sep = ", ";
 		}
 	}
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- linux-2.2.18-pre20/arch/ppc/kernel/prom.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/prom.c	Mon Dec  3 22:14:16 2001
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/console.h>
 #include <asm/spinlock.h>
 #include <asm/prom.h>
 #include <asm/page.h>
@@ -27,6 +29,10 @@
 #include <asm/system.h>
 #include <asm/gemini.h>
 #include <asm/linux_logo.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -109,6 +115,12 @@
 
 #ifdef CONFIG_BOOTX_TEXT
 
+/*
+ * The VGA font is in the _pmac section. Can't this cause problems with CHRP
+ * using some of the prom_xxxx functions ?
+ * All this need to be moved in a separate source file anyway
+ */
+
 static void clearscreen(void);
 static void flushscreen(void);
 
@@ -116,6 +128,9 @@
 void drawstring(const char *c);
 void drawhex(unsigned long v);
 static void scrollscreen(void);
+static void prepare_disp_BAT(void);
+static void boot_console_write(struct console *co, const char *s,
+				 unsigned count);
 
 static void draw_byte(unsigned char c, long locX, long locY);
 static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
@@ -128,10 +143,28 @@
 static long				g_max_loc_X = 0;
 static long				g_max_loc_Y = 0; 
 
+unsigned long disp_BATL = 0;
+unsigned long disp_BATU = 0;
+
 #define cmapsz	(16*256)
 
 static unsigned char vga_font[cmapsz];
 
+static struct console boot_cons = {
+	"boot",
+	boot_console_write,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	CON_PRINTBUFFER,
+	0,
+	0,
+	NULL
+};
+static int boot_cons_registered = 0;
+
 #endif /* CONFIG_BOOTX_TEXT */
 
 
@@ -243,7 +276,7 @@
 	return prom_args.args[nargs];
 }
 
-__init
+/*__init*/
 void
 prom_print(const char *msg)
 {
@@ -399,6 +432,7 @@
 		}
 		
 #ifdef CONFIG_BOOTX_TEXT
+		prepare_disp_BAT();
 		prom_print(RELOC("booting...\n"));
 		flushscreen();
 #endif
@@ -573,7 +607,11 @@
 	 * is in its holding pattern code.
 	 *
 	 * -- Cort
+	 * 
+	 * This code crashes on some pmacs since the memory at 8M is not
+	 * claim'ed and so can be unmapped. -- BenH
 	 */
+	if (chrp)
 	{
 		extern void __secondary_hold(void);
 		unsigned long i;
@@ -599,7 +637,7 @@
 	}
 
 	/* look for cpus */
-	for (node = 0; prom_next_node(&node);)
+	for (node = 0; chrp && prom_next_node(&node);)
 	{
 		type[0] = 0;
 		call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
@@ -642,6 +680,7 @@
 	if (!chrp && RELOC(disp_bi)) {
 		RELOC(prom_stdout) = 0;
 		clearscreen();
+		prepare_disp_BAT();
 		prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
 	}
 #endif
@@ -692,9 +731,50 @@
 	drawhex(val);
 	drawstring("\n");
 }
+
+/* Calc BAT values for mapping the display and store them
+ * in disp_BATH and disp_BATL. Those values are then used
+ * from head.S to map the display during identify_machine()
+ * and MMU_Init()
+ * 
+ * For now, the display is mapped in place (1:1). This should
+ * be changed if the display physical address overlaps
+ * KERNELBASE, which is fortunately not the case on any machine
+ * I know of. This mapping is temporary and will disappear as
+ * soon as the setup done by MMU_Init() is applied
+ * 
+ * For now, we align the BAT and then map 8Mb on 601 and 16Mb
+ * on other PPCs. This may cause trouble if the framebuffer
+ * is really badly aligned, but I didn't encounter this case
+ * yet.
+ */
+__init
+static void
+prepare_disp_BAT(void)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
+	unsigned long addr = (unsigned long)bi->dispDeviceBase;
+	
+	if ((_get_PVR() >> 16) != 1) {
+		/* 603, 604, G3, G4, ... */
+		addr &= 0xFF000000UL;
+		RELOC(disp_BATU) = addr | (BL_16M<<2) | 2;
+		RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
+	} else {
+		/* 601 */
+		addr &= 0xFF800000UL;
+		RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+		RELOC(disp_BATL) = addr | BL_8M | 0x40;
+	}
+	bi->logicalDisplayBase = bi->dispDeviceBase;
+}
+
 #endif
 
-static int prom_set_color(ihandle ih, int i, int r, int g, int b)
+__init
+static int
+prom_set_color(ihandle ih, int i, int r, int g, int b)
 {
 	struct prom_args prom_args;
 	unsigned long offset = reloc_offset();
@@ -729,7 +809,7 @@
 	ihandle ih;
 	int i;
 	unsigned long offset = reloc_offset();
-	char type[16], *path;
+	char type[16], *path, name[32];
 	static unsigned char default_colors[] = {
 		0x00, 0x00, 0x00,
 		0x00, 0x00, 0xaa,
@@ -757,6 +837,12 @@
 			  type, sizeof(type));
 		if (strcmp(type, RELOC("display")) != 0)
 			continue;
+		name[0] = 0;
+		call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
+			  name, sizeof(name));
+		if (!strcmp(name, RELOC("offscreen-display")))
+	    		continue;
+
 		/* It seems OF doesn't null-terminate the path :-( */
 		path = (char *) mem;
 		memset(path, 0, 256);
@@ -1189,7 +1275,7 @@
 		    ((node->name && !strcmp(node->name, "open-pic")) ||
 		     !node->name)) {
 		    for (i = 0; i < np->n_intrs; ++i)
-			np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
+			np->intrs[i].line = np->intrs[i].line + NUM_8259_INTERRUPTS;
 		}
 		return mem_start;
 	    }
@@ -1492,7 +1578,7 @@
 			/* CHRP machines */
 			np->n_intrs = l / (2 * sizeof(int));
 			for (i = 0; i < np->n_intrs; ++i) {
-				np->intrs[i].line = openpic_to_irq(*ip++);
+				np->intrs[i].line = (*ip++) + NUM_8259_INTERRUPTS;
 				np->intrs[i].sense = *ip++;
 			}
 		}
@@ -1637,9 +1723,17 @@
 	int l;
 	
 	for (np = allnodes; np != 0; np = np->allnext) {
-		char *pname = np->parent ?
-			(char *)get_property(np->parent, "name", &l) : 0;
-		if (pname && strcmp(pname, "mac-io") == 0)
+		int in_macio = 0;
+		struct device_node* parent = np->parent;
+		while(parent) {
+			char *pname = (char *)get_property(parent, "name", &l);
+			if (pname && strcmp(pname, "mac-io") == 0) {
+				in_macio = 1;
+				break;
+			}
+			parent = parent->parent;
+		}
+		if (in_macio)
 			continue;
 		reg = (unsigned int *) get_property(np, "reg", &l);
 		if (reg == 0 || l < sizeof(struct reg_property))
@@ -1757,7 +1851,7 @@
 	struct property *pp;
 
 	for (pp = np->properties; pp != 0; pp = pp->next)
-		if (strcmp(pp->name, name) == 0) {
+		if (pp->name && strcmp(pp->name, name) == 0) {
 			if (lenp != 0)
 				*lenp = pp->length;
 			return pp->value;
@@ -1901,11 +1995,30 @@
 void
 map_bootx_text(void)
 {
+	unsigned long base, offset, size;
 	if (disp_bi == 0)
 		return;
-	disp_bi->logicalDisplayBase =
-		ioremap((unsigned long) disp_bi->dispDeviceBase,
-			disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
+	base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL;
+	offset = ((unsigned long) disp_bi->dispDeviceBase) - base;
+	size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset
+		+ disp_bi->dispDeviceRect[0];
+	disp_bi->logicalDisplayBase = ioremap(base, size) + offset;
+}
+
+__init
+void
+install_boot_console(void)
+{
+	register_console(&boot_cons);
+	boot_cons_registered = 1;
+}
+
+void
+remove_boot_console(void)
+{
+	if (boot_cons_registered)
+		unregister_console(&boot_cons);
+	boot_cons_registered = 0;
 }
 
 /* Calc the base address of a given point (x,y) */
@@ -1981,7 +2094,11 @@
 	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 						(bi->dispDeviceDepth >> 3)) >> 2;
 	int i,j;
-	
+
+#ifdef CONFIG_POWERMAC
+	pmu_suspend();
+#endif
+
 	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
 	{
 		unsigned long *src_ptr = src;
@@ -1998,6 +2115,10 @@
 			*(dst_ptr++) = 0;
 		dst += (bi->dispDeviceRowBytes >> 2);
 	}
+
+#ifdef CONFIG_POWERMAC
+	pmu_resume();
+#endif
 }
 
 __pmac
@@ -2041,6 +2162,16 @@
 	while (*c)
 		drawchar(*c++);
 }
+
+#ifdef CONFIG_BOOTX_TEXT
+__pmac
+static void boot_console_write(struct console *co, const char *s,
+				 unsigned count)
+{
+	while(count--)
+		drawchar(*s++);
+}
+#endif
 
 __pmac
 void
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- linux-2.2.18-pre20/arch/ppc/kernel/setup.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/setup.c	Mon Dec  3 22:14:16 2001
@@ -31,6 +31,7 @@
 #endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
+#include <asm/uaccess.h>
 
 extern void pmac_init(unsigned long r3,
                       unsigned long r4,
@@ -68,9 +69,6 @@
                       unsigned long r6,
                       unsigned long r7);
 
-#ifdef CONFIG_BOOTX_TEXT
-extern void map_bootx_text(void);
-#endif
 #ifdef CONFIG_XMON
 extern void xmon_map_scc(void);
 #endif
@@ -98,6 +96,12 @@
 
 struct machdep_calls ppc_md;
 
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
 
 /* copy of the residual data */
 #ifndef CONFIG_MBX
@@ -313,19 +317,11 @@
 			       (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
 
 		len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
-			       (CD(loops_per_jiffy*HZ)+2500)/500000,
-			       (CD(loops_per_jiffy*HZ)+2500)/5000 % 100);
+			       (CD(loops_per_jiffy)+2500)/(500000/HZ),
+			       (CD(loops_per_jiffy)+2500)/(5000/HZ) % 100);
 		bogosum += CD(loops_per_jiffy);
 	}
 
-#ifdef __SMP__
-	if ( i )
-		len += sprintf(buffer+len, "\n");
-	len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
-		       (bogosum+2500)/500000,
-		       (bogosum+2500)/5000 % 100);
-#endif /* __SMP__ */
-
 	/*
 	 * Ooh's and aah's info about zero'd pages in idle task
 	 */ 
@@ -490,15 +486,21 @@
 
 	switch (_machine)
 	{
+#ifdef CONFIG_POWERMAC
 	case _MACH_Pmac:
                 pmac_init(r3, r4, r5, r6, r7);
 		break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
 	case _MACH_prep:
                 prep_init(r3, r4, r5, r6, r7);
 		break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
 	case _MACH_chrp:
                 chrp_init(r3, r4, r5, r6, r7);
 		break;
+#endif
 #ifdef CONFIG_APUS
 	case _MACH_apus:
                 apus_init(r3, r4, r5, r6, r7);
@@ -557,7 +559,8 @@
 		unsigned long val = simple_strtoul(str, NULL, 0);
 		printk(KERN_INFO "l2cr set to %lx\n", val);
 		_set_L2CR(0);
-		_set_L2CR(val);
+		if (val)
+			_set_L2CR(val);
 	}
 }
 
@@ -578,9 +581,6 @@
 	extern unsigned long find_available_memory(void);
 	extern unsigned long *end_of_DRAM;
 
-#ifdef CONFIG_BOOTX_TEXT
-	map_bootx_text();
-#endif
 
 #ifdef CONFIG_XMON
 	{
@@ -610,7 +610,15 @@
 	*memory_end_p = (unsigned long) end_of_DRAM;
 
 	ppc_md.setup_arch(memory_start_p, memory_end_p);
+
+	sort_exception_table();
 }
+
+#ifndef CONFIG_POWERMAC
+void note_bootable_part(kdev_t dev, int part, int goodness)
+{
+}
+#endif
 
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
 {
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- linux-2.2.18-pre20/arch/ppc/kernel/signal.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/signal.c	Mon Dec  3 22:14:16 2001
@@ -14,6 +14,16 @@
  *  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.
+ *
+ *
+ * 2000-04-7.
+ * Define a real-time signal frame with siginfo and ucontext
+ * structures (setup_rt_frame()).
+ * Stuck up a real-time signal frame when setting the signal
+ * frame with SA_SIGINFO flags.
+ * Add sys_rt_sigreturn() to undo the signal stack.
+ *
+ * Giovanna Ambrosini (ambrosini@lightning.ch)
  */
 
 #include <linux/sched.h>
@@ -121,13 +131,6 @@
 }
 
 
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
-{
-	printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n",
-	       current->comm,current->pid);
-	do_exit(SIGSEGV);
-}
-
 asmlinkage int
 sys_sigaltstack(const stack_t *uss, stack_t *uoss)
 {
@@ -171,13 +174,11 @@
  * When we have signals to deliver, we set up on the
  * user stack, going down from the original stack pointer:
  *	a sigregs struct
- *	one or more sigcontext structs
+ * one or more sigcontext structs with
  *	a gap of __SIGNAL_FRAMESIZE bytes
  *
  * Each of these things must be a multiple of 16 bytes in size.
  *
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
  */
 struct sigregs {
 	elf_gregset_t	gp_regs;
@@ -188,6 +189,15 @@
 	int		abigap[56];
 };
 
+struct rt_sigframe
+{
+ unsigned long _unused[2];
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+};
+
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -259,6 +269,91 @@
 	do_exit(SIGSEGV);
 }	
 
+
+/*
+ *  When we have rt signals to deliver, we set up on the
+ *  user stack, going down from the original stack pointer:
+ *    a sigregs struct
+ *    one rt_sigframe struct (siginfo + ucontext)
+ *    a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ *  Each of these things must be a multiple of 16 bytes in size.
+ *
+ */
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe *rt_sf;
+ struct sigcontext_struct sigctx;
+ struct sigregs *sr;
+ int ret;
+ elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+ sigset_t set;
+ stack_t st;
+ unsigned long prevsp;
+
+ rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
+     || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
+     || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+  goto badframe;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ rt_sf++;   /* Look at next rt_sigframe */
+ if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
+  /* Last stacked signal - restore registers -
+   * sigctx is initialized to point to the
+   * preamble frame (where registers are stored)
+   * see handle_signal()
+   */
+  sr = (struct sigregs *) sigctx.regs;
+  if (regs->msr & MSR_FP )
+   giveup_fpu(current);
+  if (copy_from_user(saved_regs, &sr->gp_regs,
+       sizeof(sr->gp_regs)))
+   goto badframe;
+  saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+   | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+  memcpy(regs, saved_regs, GP_REGS_SIZE);
+  if (copy_from_user(current->tss.fpr, &sr->fp_regs,
+       sizeof(sr->fp_regs)))
+   goto badframe;
+  /* This function sets back the stack flags into
+     the current task structure.  */
+  sys_sigaltstack(&st, NULL);
+
+  ret = regs->result;
+ } else {
+  /* More signals to go */
+  /* Set up registers for next signal handler */
+  regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
+  if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
+   goto badframe;
+  sr = (struct sigregs *) sigctx.regs;
+  regs->gpr[3] = ret = sigctx.signal;
+  /* Get the siginfo   */
+  get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
+  /* Get the ucontext */
+  get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
+  regs->gpr[6] = (unsigned long) rt_sf;
+
+  regs->link = (unsigned long) &sr->tramp;
+  regs->nip = sigctx.handler;
+  if (get_user(prevsp, &sr->gp_regs[PT_R1])
+      || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+   goto badframe;
+ }
+ return ret;
+
+badframe:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+
 /*
  * Set up a signal frame.
  */
@@ -305,6 +400,57 @@
 	do_exit(SIGSEGV);
 }
 
+
+static void
+setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
+        signed long newsp)
+{
+ struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
+
+ /* Set up preamble frame */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+  goto badframe;
+ if (regs->msr & MSR_FP)
+  giveup_fpu(current);
+ if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
+     || __copy_to_user(&frame->fp_regs, current->tss.fpr,
+         ELF_NFPREG * sizeof(double))
+ /* Set up to return from user space.
+    It calls the sc exception at offset 0x9999
+    for sys_rt_sigreturn().
+ */
+     || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */
+     || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
+  goto badframe;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+      (unsigned long) &frame->tramp[2]);
+
+ /* Retrieve rt_sigframe from stack and
+    set up registers for signal handler
+ */
+ newsp -= __SIGNAL_FRAMESIZE;
+ if (put_user(regs->gpr[1], (unsigned long *)newsp)
+     || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
+     || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
+     || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
+     || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
+  goto badframe;
+
+ regs->gpr[1] = newsp;
+ regs->gpr[6] = (unsigned long) rt_sf;
+ regs->link = (unsigned long) frame->tramp;
+
+ return;
+
+badframe:
+#if DEBUG_SIG
+ printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
+        regs, frame, newsp);
+#endif
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
 /*
  * OK, we're invoking a handler
  */
@@ -314,6 +460,7 @@
 	      unsigned long *newspp, unsigned long frame)
 {
 	struct sigcontext_struct *sc;
+ struct rt_sigframe *rt_sf;
 
 	if (regs->trap == 0x0C00 /* System Call! */
 	    && ((int)regs->result == -ERESTARTNOHAND ||
@@ -321,20 +468,47 @@
 		 !(ka->sa.sa_flags & SA_RESTART))))
 		regs->result = -EINTR;
 
-	/* Put another sigcontext on the stack */
-	*newspp -= sizeof(*sc);
-	sc = (struct sigcontext_struct *) *newspp;
-	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
-		goto badframe;
+ /* Set up Signal Frame */
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+  /* Put a Real Time Context onto stack */
+  *newspp -= sizeof(*rt_sf);
+  rt_sf = (struct rt_sigframe *) *newspp;
+  if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
+   goto badframe;
+
+  if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
+      || __put_user(&rt_sf->info, &rt_sf->pinfo)
+      || __put_user(&rt_sf->uc, &rt_sf->puc)
+      /* Put the siginfo */
+      || __copy_to_user(&rt_sf->info, info, sizeof(*info))
+      /* Create the ucontext */
+      || __put_user(0, &rt_sf->uc.uc_flags)
+      || __put_user(0, &rt_sf->uc.uc_link)
+      || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
+      || __put_user(sas_ss_flags(regs->gpr[1]),
+      &rt_sf->uc.uc_stack.ss_flags)
+      || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+      || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
+      /* mcontext.regs points to preamble register frame */
+      || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
+      || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
+   goto badframe;
+ } else {
+  /* Put another sigcontext on the stack */
+  *newspp -= sizeof(*sc);
+  sc = (struct sigcontext_struct *) *newspp;
+  if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+   goto badframe;
 
-	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
-	    || __put_user(oldset->sig[0], &sc->oldmask)
+  if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+      || __put_user(oldset->sig[0], &sc->oldmask)
 #if _NSIG_WORDS > 1
-	    || __put_user(oldset->sig[1], &sc->_unused[3])
+      || __put_user(oldset->sig[1], &sc->_unused[3])
 #endif
-	    || __put_user((struct pt_regs *)frame, &sc->regs)
-	    || __put_user(sig, &sc->signal))
-		goto badframe;
+      || __put_user((struct pt_regs *)frame, &sc->regs)
+      || __put_user(sig, &sc->signal))
+   goto badframe;
+ }
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
@@ -494,7 +668,10 @@
 	if (newsp == frame)
 		return 0;		/* no signals delivered */
 
-	setup_frame(regs, (struct sigregs *) frame, newsp);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+  setup_rt_frame(regs, (struct sigregs *) frame, newsp);
+ else
+  setup_frame(regs, (struct sigregs *) frame, newsp);
 	return 1;
 
 }
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S
--- linux-2.2.18-pre20/arch/ppc/kernel/sleep.S	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/sleep.S	Mon Dec  3 22:14:16 2001
@@ -113,8 +113,8 @@
 	stw	r4,SL_HID0(r1)
 
 	/* Set up stuff at address 0 */
-	lis	r5,wake_up@ha
-	addi	r5,r5,wake_up@l
+	lis	r5,grackle_wake_up@ha
+	addi	r5,r5,grackle_wake_up@l
 	tophys(r5,r5)
 	stw	r5,SL_PC(r1)
 	lis	r4,KERNELBASE@h
@@ -124,22 +124,28 @@
 	addi	r6,r6,MAGIC@l
 	stw	r5,0(r4)
 	stw	r6,4(r4)
+	/* Setup stuffs at 0x80-0x84 for Core99 */
+	lis	r3,core99_wake_up@ha
+	addi	r3,r3,core99_wake_up@l
+	tophys(r3,r3)
+	stw	r3,0x80(r4)
+	stw	r5,0x84(r4)
 
 /*
- * Flush the L1 data cache by reading the first 64kB of RAM
+ * Flush the L1 data cache by reading the first 128kB of RAM
  * and then flushing the same area with the dcbf instruction.
  * The L2 cache has already been disabled.
  */
-	li	r4,0x0800	/* 64kB / 32B */
+	li	r4,0x1000	/* 128kB / 32B */
 	mtctr	r4
 	lis	r4,KERNELBASE@h
 1:
 	lwz	r0,0(r4)
-	addi	r4,r4,0x0020		/* Go to start of next cache line */
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
 	bdnz	1b
 	sync
 	
-	li	r4,0x0800	/* 64k */
+	li	r4,0x1000	/* 128kB / 32B */
 	mtctr	r4
 	lis	r4,KERNELBASE@h
 1:
@@ -148,6 +154,14 @@
 	bdnz	1b
 	sync
 
+/* Turn off L1 (necessary ?) */
+	mfspr	r3,HID0
+	ori	r3,r3, HID0_ICE|HID0_DCE
+	xori	r3,r3, HID0_ICE|HID0_DCE
+	mtspr	HID0,r3
+	sync
+	isync
+
 /*
  * Set the HID0 and MSR for sleep.
  */
@@ -163,20 +177,50 @@
 1:	sync
 	mtmsr	r2
 	isync
-	b	1b
+	b	1b		
 
+	
 /* 
  * Here is the resume code.
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp).
+ */
+
+core99_wake_up:
+	mr	r1,r4
+	mfspr	r3,HID0
+	/* use rlwinm ... */
+	oris	r3,r3,HID0_SLEEP@h
+	xoris	r3,r3,HID0_SLEEP@h
+	mtspr	HID0,r3
+	sync
+	isync
+	
+	/* sanitize MSR */
+	mfmsr	r3
+	ori	r3,r3,MSR_EE|MSR_IP
+	xori	r3,r3,MSR_EE|MSR_IP
+	mtmsr	r3
+	sync
+	isync
+		
+/* 
+ * Here is the resume code for older machines.
  * r1 has the physical address of SL_PC(sp).
  */
 	
-wake_up:
-	/* Flash inval the instruction cache */
+grackle_wake_up:
+	/* Enable and then Flash inval the instruction cache */
 	mfspr	r3,HID0
-	ori	r3,r3, HID0_ICFI
-	mtspr	HID0,r3
+	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+	sync
 	isync
-	/* Restore the HID0 register.  This turns on the L1 caches. */
+	mtspr	HID0,r3
+	xori	r3,r3, HID0_ICFI|HID0_DCI
+	mtspr	HID0,r3
+	sync
+	
+	/* Restore the remaining bits of the HID0 register. */
 	subi	r1,r1,SL_PC
 	lwz	r3,SL_HID0(r1)
 	sync
@@ -239,6 +283,13 @@
 	lwz	r4,SL_IBAT3+4(r1)
 	mtibatl	3,r4
 
+	/* Flush all TLBs */
+	lis	r4, 0x1000
+1:	addic.	r4, r4, -0x1000
+	tlbie	r4
+	blt	1b
+	sync
+
 	/* restore the MSR and turn on the MMU */
 	lwz	r3,SL_MSR(r1)
 	bl	turn_on_mmu	
@@ -247,6 +298,8 @@
 	tovirt(r1,r1)
 
 	/* Restore TB */
+	lis r3,0
+	mttbl	r3
 	lwz	r3,SL_TB(r1)
 	lwz	r4,SL_TB+4(r1)
 	mttbu	r3
@@ -267,3 +320,4 @@
 	mtsrr1	r3
 	sync
 	rfi
+	sync
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- linux-2.2.18-pre20/arch/ppc/kernel/smp.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/ppc/kernel/smp.c	Mon Dec  3 22:14:16 2001
@@ -8,6 +8,8 @@
  *
  * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
  * (troy@blacklablinux.com, hozer@drgw.net)
+ * Support for PReP (Motorola MTX/MVME) and Macintosh G4 SMP 
+ * by Troy Benjegerdes (hozer@drgw.net)
  */
 
 #include <linux/kernel.h>
@@ -37,6 +39,7 @@
 #include <asm/gemini.h>
 #include <asm/residual.h>
 #include <asm/time.h>
+#include <asm/feature.h>
 #include "open_pic.h"
 
 int first_cpu_booted = 0;
@@ -46,7 +49,8 @@
 struct cpuinfo_PPC cpu_data[NR_CPUS];
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 volatile unsigned char active_kernel_processor = NO_PROC_ID;	/* Processor holding kernel spinlock		*/
-volatile unsigned long ipi_count;
+atomic_t ipi_recv;
+atomic_t ipi_sent;
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
@@ -64,6 +68,9 @@
 extern unsigned long *MotSave_SmpIar;
 extern unsigned char *MotSave_CpusState[2];
 
+/* l2 cache stuff for dual G4 macs */
+extern void core99_init_l2(void);
+ 
 /* register for interrupting the secondary processor on the powersurge */
 #define PSURGE_INTR	((volatile unsigned *)0xf80000c0)
 
@@ -114,7 +121,7 @@
 
 void smp_message_recv(int msg)
 {
-	ipi_count++;
+ 	atomic_inc(&ipi_recv);
 	
 	switch( msg )
 	{
@@ -136,6 +143,7 @@
 	}
 }
 
+#ifdef CONFIG_POWERMAC
 /*
  * As it is now, if we're sending two message at the same time
  * we have race conditions on Pmac.  The PowerSurge doesn't easily
@@ -147,10 +155,10 @@
  * rather than this.
  *  -- Cort
  */
-int pmac_smp_message[NR_CPUS];
-void pmac_smp_message_recv(void)
+int psurge_smp_message[NR_CPUS];
+void psurge_smp_message_recv(void)
 {
-	int msg = pmac_smp_message[smp_processor_id()];
+	int msg = psurge_smp_message[smp_processor_id()];
 
 	/* clear interrupt */
 	out_be32(PSURGE_INTR, ~0);
@@ -161,9 +169,9 @@
 	smp_message_recv(msg);
 
 	/* reset message */
-	pmac_smp_message[smp_processor_id()] = -1;
+	psurge_smp_message[smp_processor_id()] = -1;
 }
-
+#endif /* powermac */
 
 /*
  * 750's don't broadcast tlb invalidates so
@@ -195,49 +203,65 @@
 	smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
 }
 
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+#ifdef CONFIG_POWERMAC
+static void psurge_message_pass(int target, int msg, unsigned long data, int wait)
 {
 	int i;
 	
+	/*
+	 * IPI's on the Pmac are a hack but without reasonable
+	 * IPI hardware SMP on Pmac is a hack.
+	 *
+	 * We assume here that the msg is not -1.  If it is,
+	 * the recipient won't know the message was destined
+	 * for it. -- Cort
+	 */
+	for ( i = 0; i <= smp_num_cpus ; i++ )
+		psurge_smp_message[i] = -1;
+	switch( target )
+	{
+	case MSG_ALL:
+		psurge_smp_message[smp_processor_id()] = msg;
+		/* fall through */
+	case MSG_ALL_BUT_SELF:
+		for ( i = 0 ; i < smp_num_cpus ; i++ )
+			if ( i != smp_processor_id () )
+				psurge_smp_message[i] = msg;
+		break;
+	default:
+		psurge_smp_message[target] = msg;
+		break;
+	}
+	/* interrupt secondary processor */
+	out_be32(PSURGE_INTR, ~0);
+	out_be32(PSURGE_INTR, 0);
+	/*
+	 * Assume for now that the secondary doesn't send
+	 * IPI's -- Cort
+	 * Could be fixed with 2.4 code from Paulus -- BenH
+	 */
+	/* interrupt primary */
+	/**(volatile unsigned long *)(0xf3019000);*/
+}
+#endif /* powermac */
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ 	atomic_inc(&ipi_sent);
+
 	if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
 		return;
 
 	switch (_machine) {
+#ifdef CONFIG_POWERMAC
 	case _MACH_Pmac:
-		/*
-		 * IPI's on the Pmac are a hack but without reasonable
-		 * IPI hardware SMP on Pmac is a hack.
-		 *
-		 * We assume here that the msg is not -1.  If it is,
-		 * the recipient won't know the message was destined
-		 * for it. -- Cort
-		 */
-		for ( i = 0; i <= smp_num_cpus ; i++ )
-			pmac_smp_message[i] = -1;
-		switch( target )
-		{
-		case MSG_ALL:
-			pmac_smp_message[smp_processor_id()] = msg;
-			/* fall through */
-		case MSG_ALL_BUT_SELF:
-			for ( i = 0 ; i < smp_num_cpus ; i++ )
-				if ( i != smp_processor_id () )
-					pmac_smp_message[i] = msg;
-			break;
-		default:
-			pmac_smp_message[target] = msg;
+		/* Hack, 2.4 does it cleanly */
+		if (OpenPIC == NULL) {
+			psurge_message_pass(target, msg, data, wait);
 			break;
-		}
-		/* interrupt secondary processor */
-		out_be32(PSURGE_INTR, ~0);
-		out_be32(PSURGE_INTR, 0);
-		/*
-		 * Assume for now that the secondary doesn't send
-		 * IPI's -- Cort
-		 */
-		/* interrupt primary */
-		/**(volatile unsigned long *)(0xf3019000);*/
-		break;
+		} 
+		/* else fall through and do something sane --Troy */
+#endif
 	case _MACH_chrp:
 	case _MACH_prep:
 	case _MACH_gemini:
@@ -261,6 +285,52 @@
 	}
 }
 
+#ifdef CONFIG_POWERMAC
+static void pmac_core99_kick_cpu(int nr)
+{
+	extern void __secondary_start_psurge(void);
+
+	unsigned long save_int;
+	unsigned long flags;
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x500));
+
+	if (nr != 1)
+		return;
+
+	__save_flags(flags);
+	__cli();
+	
+	/* Save EE vector */
+	save_int = *vector;
+	
+	/* Setup fake EE vector that does	  
+	 *   b __secondary_start_psurge - KERNELBASE
+	 */   
+	*vector = 0x48000002 +
+		((unsigned long)__secondary_start_psurge - KERNELBASE);
+	
+	/* flush data cache and inval instruction cache */
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+	/* Put some life in our friend */
+	feature_core99_kick_cpu1();
+	
+	/* FIXME: We wait a bit for the CPU to take the exception, I should
+	 * instead wait for the entry code to set something for me. Well,
+	 * ideally, all that crap will be done in prom.c and the CPU left
+	 * in a RAM-based wait loop like CHRP.
+	 */
+	mdelay(1);
+	
+	/* Restore our exception vector */
+	*vector = save_int;
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+	__restore_flags(flags);
+}
+#endif /* powermac */
+
 void __init smp_boot_cpus(void)
 {
 	extern struct task_struct *current_set[NR_CPUS];
@@ -297,15 +367,21 @@
 
 	switch ( _machine )
 	{
+#ifdef CONFIG_POWERMAC
 	case _MACH_Pmac:
-		/* assume powersurge board - 2 processors -- Cort */
+		/* assum e powersurge board - 2 processors -- Cort */
+		/* or a dual G4 -- Troy */
 		cpu_nr = 2;
 		break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
 	case _MACH_chrp:
 		cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
 				 & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
 				OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
 		break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
  	case _MACH_prep:
  		/* assume 2 for now == fix later -- Johnnie */
 		if ( mot_multi )
@@ -313,10 +389,13 @@
 			cpu_nr = 2;
 			break;
 		}
+#endif
+#ifdef CONFIG_GEMINI
 	case _MACH_gemini:
                 cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
                 cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
 		break;
+#endif
 	default:
 		printk("SMP not supported on this machine.\n");
 		return;
@@ -347,30 +426,41 @@
 		/* wake up cpus */
 		switch ( _machine )
 		{
+#ifdef CONFIG_POWERMAC
 		case _MACH_Pmac:
-			/* setup entry point of secondary processor */
-			*(volatile unsigned long *)(0xf2800000) =
-				(unsigned long)__secondary_start_psurge-KERNELBASE;
-			eieio();
-			/* interrupt secondary to begin executing code */
-			out_be32(PSURGE_INTR, ~0);
-			out_be32(PSURGE_INTR, 0);
+			if (OpenPIC == NULL) {
+				/* setup entry point of secondary processor */
+				*(volatile unsigned long *)(0xf2800000) =
+					(unsigned long)__secondary_start_psurge-KERNELBASE;
+				eieio();
+				/* interrupt secondary to begin executing code */
+				out_be32(PSURGE_INTR, ~0);
+				out_be32(PSURGE_INTR, 0);
+			} else
+				pmac_core99_kick_cpu(i);
 			break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
 		case _MACH_chrp:
 			*(unsigned long *)KERNELBASE = i;
 			asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
 			break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
 		case _MACH_prep:
 			*MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE;
 			*MotSave_CpusState[1] = CPU_GOOD;
 			printk("CPU1 reset, waiting\n");
 			break;
+#endif
+#ifdef CONFIG_GEMINI
 		case _MACH_gemini:
 			openpic_init_processor( 1<<i );
 			openpic_init_processor( 0 );
 			break;
+#endif
 		}
-		
+
 		/*
 		 * wait to see if the cpu made a callin (is actually up).
 		 * use this value that I found through experimentation.
@@ -391,9 +481,9 @@
 		}
 	}
 	
-	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+	if (OpenPIC)
 		do_openpic_setup_cpu();
-	if ( _machine == _MACH_Pmac )
+	else if ( _machine == _MACH_Pmac )
 	{
 		/* reset the entry point so if we get another intr we won't
 		 * try to startup again */
@@ -439,10 +529,17 @@
 	 * place to stick it for now.
 	 *  -- Cort
 	 */
-	if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+	if (OpenPIC) {
 		do_openpic_setup_cpu();
+#ifdef CONFIG_POWERMAC
+ 		if ( _machine == _MACH_Pmac )
+ 			core99_init_l2();
+#endif
+ 	}
+#ifdef CONFIG_GEMINI
 	if ( _machine == _MACH_gemini )
 	        gemini_init_l2();
+#endif
 	while(!smp_commenced)
 		barrier();
 	__sti();
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- linux-2.2.18-pre20/arch/ppc/kernel/syscalls.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/syscalls.c	Mon Dec  3 22:14:16 2001
@@ -283,3 +283,14 @@
 
 	return error;
 }
+
+#ifndef CONFIG_PCI
+/*
+ * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is
+ * not defined, this file is not linked at all, so here are the "empty" versions
+ */
+asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
+asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
+asmlinkage long sys_pciconfig_iobase() { return -ENOSYS; }
+#endif
+
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- linux-2.2.18-pre20/arch/ppc/kernel/time.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/time.c	Mon Dec  3 22:14:16 2001
@@ -71,7 +71,7 @@
 {
 	int dval, d;
 	unsigned long cpu = smp_processor_id();
-	
+
 	hardirq_enter(cpu);
 #ifdef __SMP__
 	{
@@ -192,10 +192,10 @@
 
 __initfunc(void time_init(void))
 {
+	long time_offset = 0;
+
         if (ppc_md.time_init != NULL)
-        {
-                ppc_md.time_init();
-        }
+                time_offset = ppc_md.time_init();
 
 	if ((_get_PVR() >> 16) == 1) {
 		/* 601 processor: dec counts down by 128 every 128ns */
@@ -208,6 +208,12 @@
 
         xtime.tv_sec = ppc_md.get_rtc_time();
         xtime.tv_usec = 0;
+        if (time_offset) {
+        	struct timezone tz;
+        	tz.tz_minuteswest = time_offset/60;
+        	tz.tz_dsttime = 0; /* Not handled correctly by the kernel anyway */
+        	do_sys_settimeofday(NULL, &tz);
+        }
 
 	set_dec(decrementer_count);
 	/* allow updates right away */
diff -urN linux-2.2.18-pre20/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- linux-2.2.18-pre20/arch/ppc/kernel/traps.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/kernel/traps.c	Mon Dec  3 22:14:16 2001
@@ -156,9 +156,52 @@
 	_exception(SIGTRAP, regs);	
 }
 
+/* Illegal instruction emulation support.  Originally written to
+ * provide the PVR to user applications using the mfspr rd, PVR.
+ * Return non-zero if we can't emulate, or EFAULT if the associated
+ * memory access caused an access fault.  Return zero on success.
+ *
+ * There are a couple of ways to do this, either "decode" the instruction
+ * or directly match lots of bits.  In this case, matching lots of
+ * bits is faster and easier.
+ *
+ */
+#define INST_MFSPR_PVR		0x7c1f42a6
+#define INST_MFSPR_PVR_MASK	0xfc1fffff
+
+static int
+emulate_instruction(struct pt_regs *regs)
+{
+	uint    instword;
+	uint    rd;
+	int    retval;
+
+	retval = EINVAL;
+	if (!user_mode(regs))
+		return retval;
+
+	retval = EFAULT;
+	if (get_user(instword, (uint *)(regs->nip)))
+		return retval;
+
+	/* Emulate the mfspr rD, PVR.
+	 */
+	retval = EINVAL;
+	if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
+		rd = (instword >> 21) & 0x1f;
+		regs->gpr[rd] = _get_PVR();
+		retval = 0;
+	}
+	if (retval == 0)
+		regs->nip += 4;
+	return(retval);
+}
+
 void
 ProgramCheckException(struct pt_regs *regs)
 {
+	int errcode;
+
 	if (regs->msr & 0x100000) {
 		/* IEEE FP exception */
 		_exception(SIGFPE, regs);
@@ -170,7 +213,13 @@
 #endif
 		_exception(SIGTRAP, regs);
 	} else {
-		_exception(SIGILL, regs);
+		/* Try to emulate it if we should. */
+		if ((errcode = emulate_instruction(regs))) {
+			if (errcode == EFAULT)
+				_exception(SIGBUS, regs);
+			else
+				_exception(SIGILL, regs);
+		}
 	}
 }
 
diff -urN linux-2.2.18-pre20/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c
--- linux-2.2.18-pre20/arch/ppc/mm/extable.c	Fri Feb 20 18:28:21 1998
+++ linux/arch/ppc/mm/extable.c	Mon Dec  3 22:14:16 2001
@@ -7,8 +7,43 @@
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * such as the prep, pmac, chrp, etc. segments as well as the init
+ * segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+	      struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (p[0].insn < p[-1].insn) {
+			/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && el.insn < q[-1].insn);
+			*q = el;
+		}
+	}
+}
+
+void
+sort_exception_table(void)
+{
+	sort_ex_table(__start___ex_table, __stop___ex_table);
+}
 
 static inline unsigned long
 search_one_table(const struct exception_table_entry *first,
@@ -36,7 +71,7 @@
 {
 	unsigned long ret;
 
-#if 1 /*ndef CONFIG_MODULES*/
+#ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
 	if (ret) return ret;
diff -urN linux-2.2.18-pre20/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- linux-2.2.18-pre20/arch/ppc/mm/init.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/mm/init.c	Mon Dec  3 22:14:16 2001
@@ -1044,6 +1044,9 @@
  * still be merged.
  * -- Cort
  */
+#ifdef CONFIG_BOOTX_TEXT
+extern boot_infos_t *disp_bi;
+#endif
 __initfunc(void MMU_init(void))
 {
 #ifdef __SMP__
@@ -1092,7 +1095,13 @@
 			struct device_node *macio = find_devices("mac-io");
 			if (macio && macio->n_addrs)
 				base = macio->addrs[0].address;
-			setbat(0, base, base, 0x100000, IO_PAGE);
+			/* Hrm... we have it at 0x80000000 on some machines
+			 * and this is covered by the userland segment
+			 * registers. Isn't that bad ? Well, the BAT takes
+			 * precedence, but I don't like it. --BenH
+			 */
+			if (base >= 0xf0000000)
+				setbat(0, base, base, 0x100000, IO_PAGE);
 			ioremap_base = 0xf0000000;
 		}
 		break;
@@ -1131,6 +1140,10 @@
         ioremap(0x80000000, 0x4000);
         ioremap(0x81000000, 0x4000);
 #endif /* CONFIG_8xx */
+#ifdef CONFIG_BOOTX_TEXT
+	if (_machine == _MACH_Pmac)
+		map_bootx_text();
+#endif
 }
 
 /*
diff -urN linux-2.2.18-pre20/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- linux-2.2.18-pre20/arch/ppc/xmon/start.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/ppc/xmon/start.c	Mon Dec  3 22:14:16 2001
@@ -467,3 +467,15 @@
     *p = 0;
     return str;
 }
+
+void
+xmon_enter(void)
+{
+	pmu_suspend();
+}
+
+void
+xmon_leave(void)
+{
+	pmu_resume();
+}
diff -urN linux-2.2.18-pre20/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
--- linux-2.2.18-pre20/arch/ppc/xmon/xmon.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/xmon/xmon.c	Mon Dec  3 22:14:16 2001
@@ -86,6 +86,9 @@
 extern int setjmp(u_int *);
 extern void longjmp(u_int *, int);
 
+extern void xmon_enter(void);
+extern void xmon_leave(void);
+
 #define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
 
 static char *help_string = "\
@@ -139,6 +142,7 @@
 	msr = get_msr();
 	set_msr(msr & ~0x8000);	/* disable interrupts */
 	remove_bpts();
+	xmon_enter();
 	excprint(excp);
 	cmd = cmds(excp);
 	if (cmd == 's') {
@@ -151,6 +155,7 @@
 		xmon_trace = 0;
 		insert_bpts();
 	}
+	xmon_leave();
 	set_msr(msr);		/* restore interrupt enable */
 }
 
diff -urN linux-2.2.18-pre20/arch/s390/boot/ipleckd.S linux/arch/s390/boot/ipleckd.S
--- linux-2.2.18-pre20/arch/s390/boot/ipleckd.S	Mon Dec  3 22:14:07 2001
+++ linux/arch/s390/boot/ipleckd.S	Mon Dec  3 22:14:16 2001
@@ -11,6 +11,8 @@
 # FIXME:	 should insert zeroes into memory when filling holes
 # FIXME:	 calculate blkpertrack from rdc data and blksize
 
+# change 09/20/00       removed obsolete store of ipldevice to textesegment
+
 # Usage of registers
 # r1:	ipl subchannel ( general use, dont overload without save/restore !)
 # r10:
@@ -44,10 +46,10 @@
 	stsch	.Lrdcdata
 	oi      .Lrdcdata+5,0x84        # enable ssch and multipath mode
 .Lecs:  xi	.Lrdcdata+27,0x01	# enable concurrent sense
-	msch	.Lrdcdata	
+	msch	.Lrdcdata
         xi      .Lprgn,6                # restore Wait and d/a bit in PCnew PSW
 	l	%r2,.Lparm
-	mvc     0x0(8,%r2),.Lnull       # set parmarea to null
+	mvc     0x0(8,%r2),.Lnull	# set parmarea to null
 	lctl	%c6,%c6,.Lc6     	# enable all interrupts
 .Lrdc:					# read device characteristics
 	la	%r6,.Lrdcccw     
@@ -94,7 +96,7 @@
 .Lzeroes:
 	lr	%r2,%r3
 .L001:	slr	%r3,%r3
-	icm	%r3,3,.Lcountarea+6     # get blocksize
+	icm	%r3,3,.Lcountarea+6	# get blocksize
 	slr	%r5,%r5			# no bytes to move
 .L008:	mvcle	%r2,%r4,0   		# fill zeroes to storage
 	jo	.L008			# until block is filled
@@ -111,10 +113,10 @@
 	mvc	0x600(256,%r3),0x180(%r4)
 	mvc	0x700(256,%r3),0x280(%r4)
 .Lrunkern:
-	lhi	%r2,17
-	sll	%r2,12
-	st	%r1,0xc6c(%r2)		# store iplsubchannel to lowcore
-	st	%r1,0xc6c		# store iplsubchannel to lowcore
+#	lhi	%r2,17
+#	sll	%r2,12
+#	st	%r1,0xc6c(%r2)		# store iplsubchannel to lowcore
+#	st	%r1,0xc6c		# store iplsubchannel to lowcore
 	br	%r3
 # This function does the start IO
 # r2:	number of first block to read ( input by caller )
@@ -140,8 +142,8 @@
 	lr	%r15,%r4		# save number or blocks
 	slr	%r7,%r7
 	icm	%r7,3,.Lrdcdata+14      # load heads to r7
-	lhi     %r6,9
-	clc     .Lrdcdata+3(2),.L9345
+	lhi	%r6,9
+	clc	.Lrdcdata+3(2),.L9345
 	je	.L011
 	lhi	%r6,10
 	clc	.Lrdcdata+3(2),.L3380
@@ -149,7 +151,7 @@
 	lhi	%r6,12
 	clc	.Lrdcdata+3(2),.L3390     
 	je	.L011			
-        bras 	%r14,.Ldisab
+	bras 	%r14,.Ldisab
 .L011:	
 	# loop for nbl times
 .Lrdloop:	
diff -urN linux-2.2.18-pre20/arch/s390/config.in linux/arch/s390/config.in
--- linux-2.2.18-pre20/arch/s390/config.in	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/config.in	Mon Dec  3 22:14:16 2001
@@ -8,6 +8,7 @@
 mainmenu_option next_comment
 comment 'Code maturity level options'
 bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
 endmenu
 
 mainmenu_option next_comment
diff -urN linux-2.2.18-pre20/arch/s390/defconfig linux/arch/s390/defconfig
--- linux-2.2.18-pre20/arch/s390/defconfig	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/defconfig	Mon Dec  3 22:14:16 2001
@@ -7,6 +7,7 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_PROCESS_DEBUG=n
 
 #
 # Processor type and features
@@ -81,7 +82,7 @@
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
 # CONFIG_IP_ROUTER is not set
diff -urN linux-2.2.18-pre20/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c
--- linux-2.2.18-pre20/arch/s390/kernel/cpcmd.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/cpcmd.c	Mon Dec  3 22:14:16 2001
@@ -8,7 +8,7 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <asm/string.h>
+#include <linux/string.h>
 #include <asm/ebcdic.h>
 
 void cpcmd(char *cmd, char *response, int rlen)
diff -urN linux-2.2.18-pre20/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c
--- linux-2.2.18-pre20/arch/s390/kernel/debug.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/debug.c	Mon Dec  3 22:14:16 2001
@@ -1,285 +1,1120 @@
+/*
+ *  arch/s390/kernel/debug.c
+ *   S/390 debug facility
+ *
+ *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ *                             IBM Corporation
+ *    Author(s): Michael Holzheu (holzheu@de.ibm.com),
+ *               Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *
+ *    Bugreports to: <Linux390@de.ibm.com>
+ */
+
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
 #include <asm/ebcdic.h>
-#include <asm/debug.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 #ifdef MODULE
 #include <linux/module.h>
 #endif
 
-#include <asm/ebcdic.h>
+#include <asm/debug.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#if defined(CONFIG_ARCH_S390)
+#define DEBUG_PROC_HEADER_SIZE 38
+#endif
+
+#define ADD_BUFFER 1000
+
+/* typedefs */
+
+typedef struct file_private_info {
+	loff_t len;			/* length of output in byte */
+	int size;			/* size of buffer for output */
+	char *data;			/* buffer for output */
+	debug_info_t *debug_info;	/* the debug information struct */
+	struct debug_view *view;	/* used view of debug info */
+} file_private_info_t;
+
+extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+
+/* internal function prototyes */
+
+static int debug_init(void);
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+			       int size, struct debug_view *view);
+static ssize_t debug_output(struct file *file, char *user_buf,
+			    size_t user_len, loff_t * offset);
+static ssize_t debug_input(struct file *file, const char *user_buf,
+			   size_t user_len, loff_t * offset);
+static int debug_open(struct inode *inode, struct file *file);
+static int debug_close(struct inode *inode, struct file *file);
+static struct proc_dir_entry 
+*debug_create_proc_dir_entry(struct proc_dir_entry *root,
+			     const char *name, mode_t mode,
+			     struct inode_operations *iops,
+			     struct file_operations *fops);
+static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
+					struct proc_dir_entry *entry);
+static void debug_info_get(debug_info_t *);
+static void debug_info_put(debug_info_t *);
+static int debug_prolog_level_fn(debug_info_t * id,
+				 struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+				struct file *file, const char *user_buf,
+				size_t user_buf_size, loff_t * offset);
+static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
+			       char *out_buf, const char *in_buf);
+static int debug_ascii_format_fn(debug_info_t * id,
+				 struct debug_view *view, char *out_buf,
+				 const char *in_buf);
+static int debug_ebcdic_format_fn(debug_info_t * id,
+				  struct debug_view *view, char *out_buf,
+				  const char *in_buf);
+
+/* globals */
+
+struct debug_view debug_ascii_view = {
+	"ascii",
+	NULL,
+	&debug_dflt_header_fn,
+	&debug_ascii_format_fn,
+	NULL
+};
+
+struct debug_view debug_ebcdic_view = {
+	"ebcdic",
+	NULL,
+	&debug_dflt_header_fn,
+	&debug_ebcdic_format_fn,
+	NULL
+};
+
+struct debug_view debug_hex_view = {
+	"hex",
+	NULL,
+	&debug_dflt_header_fn,
+	&debug_hex_format_fn,
+	NULL
+};
+
+struct debug_view debug_level_view = {
+	"level",
+	&debug_prolog_level_fn,
+	NULL,
+	NULL,
+	&debug_input_level_fn
+};
+
+/* static globals */
+
+static debug_info_t debug_areas[DEBUG_MAX_AREAS];
+static debug_info_t *free_area = 0;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+static struct semaphore debug_lock = MUTEX;
+#else
+DECLARE_MUTEX(debug_lock);
+#endif
 
-debug_info_t debug_areas[MAX_DEBUG_AREAS] = { {NULL, },};
-debug_info_t *free_area = 0;
 static int initialized = 0;
 
-static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED;
+static struct file_operations debug_file_ops = {
+	read:    debug_output,
+	write:   debug_input,	
+	open:    debug_open,
+	release: debug_close,
+};
+
+static struct inode_operations debug_inode_ops = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+	default_file_ops: &debug_file_ops,	/* file ops */
+#endif
+};
+
+
+static struct proc_dir_entry *debug_proc_root_entry;
+
+
+/* functions */
+
+/*
+ * debug_info_get
+ * - increments reference count for debug-info
+ */
+
+static void debug_info_get(debug_info_t * db_info)
+{
+	if (db_info)
+		atomic_inc(&db_info->ref_count);
+}
+
+/*
+ * debug_info_put:
+ * - decreases reference count for debug-info and frees it if necessary
+ */
+
+static void debug_info_put(debug_info_t *db_info)
+{
+	int i;
+
+	if (!db_info)
+		return;
+	if (atomic_dec_and_test(&db_info->ref_count)) {
+		printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
+		       db_info, db_info->name);
+		for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+			if (db_info->views[i] != NULL)
+				debug_delete_proc_dir_entry
+				    (db_info->proc_root_entry,
+				     db_info->proc_entries[i]);
+		}
+		debug_delete_proc_dir_entry(debug_proc_root_entry,
+					    db_info->proc_root_entry);
+		for (i = 0; i < db_info->nr_areas; i++) {
+			free_pages((unsigned long) db_info->areas[i],
+				   db_info->page_order);
+		}
+		kfree(db_info->areas);
+		db_info->areas = NULL;
+		*((debug_info_t **) db_info) = free_area;
+		free_area = db_info;
+	}
+}
+
 
-debug_info_t *
-debug_register (char *name, int page_order, int nr_areas)
+/*
+ * debug_output:
+ * - called for user read()
+ * - copies formated output form private_data of the file
+ *   handle to the user buffer
+ */
+
+static ssize_t debug_output(struct file *file,	/* file descriptor */
+			    char *user_buf,	/* user buffer */
+			    size_t user_len,	/* length of buffer */
+			    loff_t *offset	/* offset in the file */ )
 {
-  debug_info_t *rc = 0;
-  int i;
-  long flags;
-
-  if ( ! initialized ){
-    debug_init();
-    initialized = 1;
-  }
-  if (!free_area)
-    {
-      printk (KERN_WARNING "No free debug area\n");
-      return NULL;
-    }
-  spin_lock_irqsave (&debug_lock, flags);
-  rc = free_area;
-  free_area = *((debug_info_t **) rc);
-
-  memset(rc, 0, nr_areas * sizeof(debug_info_t));
-  rc->areas = (debug_entry_t **) kmalloc (nr_areas *
-					  sizeof (debug_entry_t *),
-					  GFP_ATOMIC);
-  if (!rc->areas)
-    {
-      goto noareas;
-    }
-
-  for (i = 0; i < nr_areas; i++)
-    {
-      rc->areas[i] = (debug_entry_t *) __get_free_pages (GFP_ATOMIC,
-							 page_order);
-      if (!rc->areas[i])
+	loff_t len;
+	int rc;
+	file_private_info_t *p_info;
+
+	p_info = ((file_private_info_t *) file->private_data);
+	if (*offset >= p_info->len) {
+		return 0;	/* EOF */
+	} else {
+		len = MIN(user_len, (p_info->len - *offset));
+		if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
+			return rc;;
+		(*offset) += len;
+		return len;	/* number of bytes "read" */
+	}
+}
+
+/*
+ * debug_input:
+ * - called for user write()
+ * - calls input function of view
+ */
+
+static ssize_t debug_input(struct file *file,
+			   const char *user_buf, size_t length,
+			   loff_t *offset)
+{
+	int rc = 0;
+	file_private_info_t *p_info;
+
+	down(&debug_lock);
+	p_info = ((file_private_info_t *) file->private_data);
+	if (p_info->view->input_proc)
+		rc = p_info->view->input_proc(p_info->debug_info,
+					      p_info->view, file, user_buf,
+					      length, offset);
+	up(&debug_lock);
+	return rc;		/* number of input characters */
+}
+
+/*
+ * debug_format_output:
+ * - calls prolog, header and format functions of view to format output
+ */
+
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+			       int size, struct debug_view *view)
+{
+	int len = 0;
+	int i, j;
+	int nr_of_entries;
+	debug_entry_t *act_entry;
+
+	/* print prolog */
+	if (view->prolog_proc)
+		len += view->prolog_proc(debug_area, view, buf);
+	/* print debug records */
+	if (!(view->format_proc) && !(view->header_proc))
+		goto out;
+	nr_of_entries = PAGE_SIZE / debug_area->entry_size
+			<< debug_area->page_order;
+	for (i = 0; i < debug_area->nr_areas; i++) {
+		act_entry = debug_area->areas[i];
+		for (j = 0; j < nr_of_entries; j++) {
+			if (act_entry->id.fields.used == 0)
+				break;	/* empty entry */
+			if (view->header_proc)
+				len += view->header_proc(debug_area, view, i,
+						         act_entry, buf + len);
+			if (view->format_proc)
+				len += view->format_proc(debug_area, view,
+						         buf + len,
+						         act_entry->data);
+			len += sprintf(buf + len, "\n");
+			if (len > size) {
+				printk(KERN_ERR
+				"debug: error -- memory exceeded for (%s/%s)\n",
+				debug_area->name, view->name);
+				printk(KERN_ERR "debug: fix view %s!!\n",
+				       view->name);
+				printk(KERN_ERR
+				"debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
+				i, debug_area->nr_areas - 1, j,
+				nr_of_entries - 1);
+				goto out;
+			}
+			act_entry = (debug_entry_t *) (((char *) act_entry) +
+					       debug_area->entry_size);
+		}
+	}
+      out:
+	return len;
+}
+
+
+/*
+ * debug_open:
+ * - called for user open()
+ * - copies formated output to private_data area of the file
+ *   handle
+ */
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+	int i, j = 0, size = 0, rc = 0, f_entry_size = 0;
+	file_private_info_t *p_info;
+
+#ifdef DEBUG
+	printk("debug_open\n");
+#endif
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	down(&debug_lock);
+
+	/* find debug log and view */
+
+	for (i = 0; i < DEBUG_MAX_AREAS; i++) {
+		if (debug_areas[i].areas == NULL)
+			continue;	/* not in use */
+		for (j = 0; j < DEBUG_MAX_VIEWS; j++) {
+			if (debug_areas[i].views[j] == NULL)
+				continue;
+			else if (debug_areas[i].proc_entries[j]->low_ino ==
+				 file->f_dentry->d_inode->i_ino) {
+				goto found;	/* found view ! */
+			}
+		}
+	}
+	/* no entry found */
+	rc = -EINVAL;
+	goto out;
+      found:
+	if ((file->private_data =
+	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+		printk(KERN_ERR "debug_open: kmalloc failed\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	p_info = (file_private_info_t *) file->private_data;
+
+	/*
+	 * the size for the formated output is calculated
+	 * with the following formula:
+	 *
+	 *   prolog-size
+	 *   +
+	 *   (record header size + record data field size)
+	 *   * number of entries per page
+	 *   * number of pages per area
+	 *   * number of areas
+	 */
+
+	if (debug_areas[i].views[j]->prolog_proc)
+		size +=
+		    debug_areas[i].views[j]->prolog_proc(&debug_areas[i],
+							 debug_areas[i].
+							 views[j], NULL);
+
+	if (debug_areas[i].views[j]->header_proc)
+		f_entry_size =
+		    debug_areas[i].views[j]->header_proc(&debug_areas[i],
+							 debug_areas[i].
+							 views[j], 0, NULL,
+							 NULL);
+	if (debug_areas[i].views[j]->format_proc)
+		f_entry_size +=
+		    debug_areas[i].views[j]->format_proc(&debug_areas[i],
+							 debug_areas[i].
+							 views[j], NULL,
+							 NULL);
+	if (f_entry_size)
+		f_entry_size += 1;	/* \n in each line */
+
+
+	size += f_entry_size 
+		* (PAGE_SIZE / debug_areas[i].entry_size
+		<< debug_areas[i].page_order)
+		* debug_areas[i].nr_areas + 1;	/* terminating \0 */
+#ifdef DEBUG
+	printk("debug_open: size: %i\n", size);
+#endif
+
+	/* alloc some bytes more to be safe against bad views */
+	if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
+		printk(KERN_ERR "debug_open: vmalloc failed\n");
+		vfree(file->private_data);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	p_info->size = size;
+	p_info->debug_info = &debug_areas[i];
+	p_info->view = debug_areas[i].views[j];
+
+	spin_lock_irq(&debug_areas[i].lock);
+
+	p_info->len =
+	    debug_format_output(&debug_areas[i], p_info->data, size,
+				debug_areas[i].views[j]);
+#ifdef DEBUG
 	{
-	  for (i--; i >= 0; i--)
-	    {
-	      free_pages ((unsigned long) rc->areas[i], page_order);
-	    }
-	  goto nopages;
-	}
-    }
-  rc->page_order = page_order;
-  rc->nr_areas = nr_areas;
-  rc->name = kmalloc (strlen (name) + 1, GFP_ATOMIC);
-  strncpy (rc->name, name, strlen (name));
-  ASCEBC(rc->name, strlen (name));
-  rc->name[strlen (name)] = 0;
-
-  rc->active_entry = kmalloc (nr_areas, GFP_ATOMIC);
-  memset(rc->active_entry, 0, nr_areas * sizeof(int));
-  rc->level=3;
-  printk (KERN_INFO "reserved %d areas of %d pages for debugging %s\n",
-	  nr_areas, 1 << page_order, name);
-  goto exit;
-
-nopages:
-noareas:
-  free_area = rc;
-exit:
-  spin_unlock_irqrestore (&debug_lock, flags);
-  return rc;
-}
-
-void
-debug_unregister (debug_info_t * id, char *name)
-{
-  int i = id->nr_areas;
-  long flags;
-  spin_lock_irqsave (&debug_lock, flags);
-  printk (KERN_INFO "freeing debug area %p named '%s'\n", id, name);
-  if (strncmp (name, id->name, strlen (name)))
-    {
-      printk (KERN_ERR "name '%s' does not match against '%s'\n",
-	      name, id->name);
-    }
-  for (i--; i >= 0; i--)
-    {
-      free_pages ((unsigned long) id->areas[i], id->page_order);
-    }
-  kfree (id->areas);
-  kfree (id->name);
-  *((debug_info_t **) id) = free_area;
-  free_area = id;
-  spin_unlock_irqrestore (&debug_lock, flags);
-  return;
-}
-
-static inline void
-proceed_active_entry (debug_info_t * id)
-{
-  id->active_entry[id->active_area] =
-    (id->active_entry[id->active_area]++) %
-    ((PAGE_SIZE / sizeof (debug_entry_t)) << (id->page_order));
-}
-
-static inline void
-proceed_active_area (debug_info_t * id)
-{
-  id->active_area = (id->active_area++) % id->nr_areas;
-}
-
-static inline debug_entry_t *
-get_active_entry (debug_info_t * id)
-{
-  return &id->areas[id->active_area][id->active_entry[id->active_area]];
-}
-
-static inline debug_entry_t *
-debug_common ( debug_info_t * id )
-{
-  debug_entry_t * active;
-  proceed_active_entry (id);
-  active = get_active_entry (id);
-  STCK (active->id.stck);
-  active->id.stck = active->id.stck >> 4;
-  active->id.fields.cpuid = smp_processor_id ();
-  active->caller = __builtin_return_address (0);
-  return active;
-}
-
-void
-debug_event (debug_info_t * id, int level, unsigned int tag)
-{
-  long flags;
-  debug_entry_t *active;
-  if (!id)
-    {
-      return;
-    }
-  if (level < id->level)
-    {
-      return;
-    }
-  spin_lock_irqsave (&id->lock, flags);
-  active = debug_common(id);
-  active->tag.tag = tag;
-  spin_unlock_irqrestore (&id->lock, flags);
-  return;
-}
-
-void
-debug_text_event (debug_info_t * id, int level, char tag[4])
-{
-  long flags;
-  debug_entry_t *active;
-  if (!id)
-    {
-      return;
-    }
-  if (level < id->level)
-    {
-      return;
-    }
-  spin_lock_irqsave (&id->lock, flags);
-  active = debug_common(id);
-  strncpy ( active->tag.text, tag, 4);
-  ASCEBC (active->tag.text, 4 );
-  spin_unlock_irqrestore (&id->lock, flags);
-  return;
-}
-
-void
-debug_exception (debug_info_t * id, int level, unsigned int tag)
-{
-  long flags;
-  debug_entry_t *active;
-  if (!id)
-    {
-      return;
-    }
-  if (level < id->level)
-    {
-      return;
-    }
-  spin_lock_irqsave (&id->lock, flags);
-  active = debug_common(id);
-  active->tag.tag = tag;
-  proceed_active_area (id);
-  spin_unlock_irqrestore (&id->lock, flags);
-
-  return;
-}
-
-void
-debug_text_exception (debug_info_t * id, int level, char tag[4])
-{
-  long flags;
-  debug_entry_t *active;
-  if (!id)
-    {
-      return;
-    }
-  if (level < id->level)
-    {
-      return;
-    }
-  spin_lock_irqsave (&id->lock, flags);
-  active = debug_common(id);
-  strncpy ( active->tag.text, tag, 4);
-  ASCEBC (active->tag.text, 4 );
-  proceed_active_area (id);
-  spin_unlock_irqrestore (&id->lock, flags);
-  return;
-}
-
-int
-debug_init (void)
-{
-  int rc = 0;
-  int i;
-  for (i = 0; i < MAX_DEBUG_AREAS - 1; i++)
-    {
-      *(debug_info_t **) (&debug_areas[i]) =
-	(debug_info_t *) (&debug_areas[i + 1]);
-    }
-  *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL;
-  free_area = &(debug_areas[0]);
-  printk (KERN_INFO "%d areas reserved for debugging information\n",
-	  MAX_DEBUG_AREAS);
-  return rc;
+		int ilen = p_info->len;
+		printk("debug_open: len: %i\n", ilen);
+	}
+#endif
+
+	spin_unlock_irq(&debug_areas[i].lock);
+	debug_info_get(&debug_areas[i]);
+
+      out:
+	up(&debug_lock);
+#ifdef MODULE
+	if (rc != 0)
+		MOD_DEC_USE_COUNT;
+#endif
+	return rc;
+}
+
+/*
+ * debug_close:
+ * - called for user close()
+ * - deletes  private_data area of the file handle
+ */
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+	file_private_info_t *p_info;
+#ifdef DEBUG
+	printk("debug_close\n");
+#endif
+	down(&debug_lock);
+	p_info = (file_private_info_t *) file->private_data;
+	debug_info_put(p_info->debug_info);
+	if (p_info->data) {
+		vfree(p_info->data);
+		kfree(file->private_data);
+	}
+	up(&debug_lock);
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;		/* success */
+}
+
+/*
+ * debug_create_proc_dir_entry:
+ * - initializes proc-dir-entry and registers it
+ */
+
+static struct proc_dir_entry *debug_create_proc_dir_entry
+    (struct proc_dir_entry *root, const char *name, mode_t mode,
+     struct inode_operations *iops, struct file_operations *fops) 
+{
+	struct proc_dir_entry *rc = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+	const char *fn = name;
+	int len;
+	len = strlen(fn);
+
+	rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry)
+					       + len + 1, GFP_ATOMIC);
+	if (!rc)
+		goto out;
+
+	memset(rc, 0, sizeof(struct proc_dir_entry));
+	memcpy(((char *) rc) + sizeof(*rc), fn, len + 1);
+	rc->name = ((char *) rc) + sizeof(*rc);
+	rc->namelen = len;
+	rc->low_ino = 0, rc->mode = mode;
+	rc->nlink = 1;
+	rc->uid = 0;
+	rc->gid = 0;
+	rc->size = 0;
+	rc->get_info = NULL;
+	rc->ops = iops;
+
+	proc_register(root, rc);
+#else
+	rc = create_proc_entry(name, mode, root);
+	if (!rc)
+		goto out;
+	if (fops)
+		rc->proc_fops = fops;
+#endif
+
+      out:
+	return rc;
+}
+
+
+/*
+ * delete_proc_dir_entry:
+ */
+
+static void debug_delete_proc_dir_entry
+    (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) 
+{
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+	proc_unregister(root, proc_entry->low_ino);
+	kfree(proc_entry);
+#else
+	remove_proc_entry(proc_entry->name, root);
+#endif
 }
 
+/*
+ * debug_register:
+ * - creates and initializes debug area for the caller
+ * - returns handle for debug area
+ */
+
+debug_info_t *debug_register
+    (char *name, int page_order, int nr_areas, int buf_size) 
+{
+	debug_info_t *rc = NULL;
+	int i;
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	if (!initialized)
+		debug_init();
+	down(&debug_lock);
+	if (!free_area) {
+		printk(KERN_WARNING "debug: no free debug area for %s\n",
+		       name);
+		goto out;
+	}
+	rc = free_area;
+	free_area = *((debug_info_t **) rc);
+	rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+					       sizeof(debug_entry_t *),
+					       GFP_ATOMIC);
+	if (!rc->areas) {
+		free_area = rc;
+		rc = NULL;
+		goto out;
+	}
+	for (i = 0; i < nr_areas; i++) {
+		rc->areas[i] =
+		    (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+						       page_order);
+		if (!rc->areas[i]) {
+			for (i--; i >= 0; i--) {
+				free_pages((unsigned long) rc->areas[i],
+					   page_order);
+			}
+			free_area = rc;
+			rc = NULL;
+			goto out;
+		} else {
+			memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+		}
+	}
+
+	rc->page_order  = page_order;
+	rc->nr_areas    = nr_areas;
+	rc->active_area = 0;
+	rc->level       = DEBUG_DEFAULT_LEVEL;
+	rc->buf_size    = buf_size;
+	rc->entry_size  = sizeof(debug_entry_t) 
+                          + buf_size - 4;  /* must subtract data[4] */
+	strncpy(rc->name, name,
+		MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+	memset(rc->active_entry, 0, nr_areas * sizeof(int));
+	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+	atomic_set(&(rc->ref_count), 0);
+	rc->proc_root_entry =
+	    debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+					S_IFDIR | S_IRUGO | S_IXUGO |
+					S_IWUSR | S_IWGRP, NULL, NULL);
+	debug_register_view(rc, &debug_level_view);
+	debug_info_get(rc);
+	printk(KERN_INFO
+	       "debug: reserved %d areas of %d pages for debugging %s\n",
+	       nr_areas, 1 << page_order, rc->name);
+      out:
+        if (rc == NULL){
+		printk(KERN_ERR "debug: debug_register failed for %s\n",name);
 #ifdef MODULE
-int
-init_module (void)
+		MOD_DEC_USE_COUNT;
+#endif
+        }
+	up(&debug_lock);
+	return rc;
+}
+
+/*
+ * debug_unregister:
+ * - give back debug area
+ */
+
+void debug_unregister(debug_info_t * id)
+{
+	if (!id)
+		goto out;
+	down(&debug_lock);
+	printk(KERN_INFO "debug: unregistering %s\n", id->name);
+	debug_info_put(id);
+	up(&debug_lock);
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+      out:
+	return;
+}
+
+
+/*
+ * proceed_active_entry:
+ * - set active entry to next in the ring buffer
+ */
+
+static inline void proceed_active_entry(debug_info_t * id)
+{
+	if ((id->active_entry[id->active_area] += id->entry_size)
+	    > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
+		id->active_entry[id->active_area] = 0;
+}
+
+/*
+ * proceed_active_area:
+ * - set active area to next in the ring buffer
+ */
+
+static inline void proceed_active_area(debug_info_t * id)
+{
+	id->active_area++;
+	id->active_area = id->active_area % id->nr_areas;
+}
+
+/*
+ * get_active_entry:
+ */
+
+static inline debug_entry_t *get_active_entry(debug_info_t * id)
+{
+	return (debug_entry_t *) ((char *) id->areas[id->active_area] +
+				  id->active_entry[id->active_area]);
+}
+
+/*
+ * debug_common:
+ * - set timestamp, caller address, cpu number etc.
+ */
+
+static inline debug_entry_t *debug_common(debug_info_t * id)
+{
+	debug_entry_t *active;
+
+	active = get_active_entry(id);
+	STCK(active->id.stck);
+	active->id.fields.cpuid = smp_processor_id();
+	active->id.fields.used = 1;
+	active->caller = __builtin_return_address(0);
+	return active;
+}
+
+/*
+ * debug_event:
+ */
+
+debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
+			   int len)
+{
+	long flags;
+	debug_entry_t *active = NULL;
+
+	if ((!id) || (level < id->level))
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	active = debug_common(id);
+	active->id.fields.exception = 0;
+	memset(active->data, 0, id->buf_size);
+	memcpy(active->data, buf, MIN(len, id->buf_size));
+	proceed_active_entry(id);
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return active;
+}
+
+/*
+ * debug_int_event:
+ */
+
+debug_entry_t *debug_int_event(debug_info_t * id, int level,
+			       unsigned int tag)
+{
+	long flags;
+	debug_entry_t *active = NULL;
+
+	if ((!id) || (level < id->level))
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	active = debug_common(id);
+	active->id.fields.exception = 0;
+	memset(active->data, 0, id->buf_size);
+	memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size));
+	proceed_active_entry(id);
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return active;
+}
+
+/*
+ * debug_text_event:
+ */
+
+debug_entry_t *debug_text_event(debug_info_t * id, int level,
+				const char *txt)
+{
+	long flags;
+	debug_entry_t *active = NULL;
+
+	if ((!id) || (level < id->level))
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	active = debug_common(id);
+	memset(active->data, 0, id->buf_size);
+	strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
+	ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
+	active->id.fields.exception = 0;
+	proceed_active_entry(id);
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return active;
+
+}
+
+/*
+ * debug_exception:
+ */
+
+debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
+			       int len)
+{
+	long flags;
+	debug_entry_t *active = NULL;
+
+	if ((!id) || (level < id->level))
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	active = debug_common(id);
+	active->id.fields.exception = 1;
+	memset(active->data, 0, id->buf_size);
+	memcpy(active->data, buf, MIN(len, id->buf_size));
+	proceed_active_entry(id);
+	proceed_active_area(id);
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return active;
+}
+
+/*
+ * debug_int_exception:
+ */
+
+debug_entry_t *debug_int_exception(debug_info_t * id, int level,
+				   unsigned int tag)
+{
+	long flags;
+	debug_entry_t *active = NULL;
+
+	if ((!id) || (level < id->level))
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	active = debug_common(id);
+	active->id.fields.exception = 1;
+	memset(active->data, 0, id->buf_size);
+	memcpy(active->data, &tag,
+	       MIN(sizeof(unsigned int), id->buf_size));
+	proceed_active_entry(id);
+	proceed_active_area(id);
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return active;
+}
+
+/*
+ * debug_text_exception:
+ */
+
+debug_entry_t *debug_text_exception(debug_info_t * id, int level,
+				    const char *txt)
+{
+	long flags;
+	debug_entry_t *active = NULL;
+
+	if ((!id) || (level < id->level))
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	active = debug_common(id);
+	memset(active->data, 0, id->buf_size);
+	strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
+	ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
+	active->id.fields.exception = 1;
+	proceed_active_entry(id);
+	proceed_active_area(id);
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return active;
+
+}
+
+/*
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
+ */
+
+int debug_init(void)
+{
+	int rc = 0;
+	int i;
+
+	down(&debug_lock);
+	if (!initialized) {
+		debug_proc_root_entry =
+		    debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT,
+						S_IFDIR | S_IRUGO | S_IXUGO
+						| S_IWUSR | S_IWGRP, NULL,
+						NULL);
+		for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) {
+			*(debug_info_t **) (&debug_areas[i]) =
+			    (debug_info_t *) (&debug_areas[i + 1]);
+		}
+		*(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL;
+		free_area = &(debug_areas[0]);
+		printk(KERN_INFO
+		       "debug: %d areas reserved for debugging information\n",
+		       DEBUG_MAX_AREAS);
+		initialized = 1;
+	}
+	up(&debug_lock);
+
+	return rc;
+}
+
+/*
+ * debug_register_view:
+ */
+
+int debug_register_view(debug_info_t * id, struct debug_view *view)
+{
+	int rc = 0;
+	int i;
+	long flags;
+	mode_t mode = S_IFREG;
+
+	if (!id)
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+		if (id->views[i] == NULL)
+			break;
+	}
+	if (i == DEBUG_MAX_VIEWS) {
+		printk(KERN_WARNING "debug: cannot register view %s/%s\n",
+			id->name,view->name);
+		printk(KERN_WARNING 
+			"debug: maximum number of views reached (%i)!\n", i);
+		rc = -1;
+	}
+	else {
+		id->views[i] = view;
+		if (view->prolog_proc || view->format_proc || view->header_proc)
+			mode |= S_IRUSR;
+		if (view->input_proc)
+			mode |= S_IWUSR;
+		id->proc_entries[i] =
+		    debug_create_proc_dir_entry(id->proc_root_entry,
+						view->name, mode,
+						&debug_inode_ops,
+						&debug_file_ops);
+		rc = 0;
+	}
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return rc;
+}
+
+/*
+ * debug_unregister_view:
+ */
+
+int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+{
+	int rc = 0;
+	int i;
+	long flags;
+
+	if (!id)
+		goto out;
+	spin_lock_irqsave(&id->lock, flags);
+	for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+		if (id->views[i] == view)
+			break;
+	}
+	if (i == DEBUG_MAX_VIEWS)
+		rc = -1;
+	else {
+		debug_delete_proc_dir_entry(id->proc_root_entry,
+					    id->proc_entries[i]);		
+		id->views[i] = NULL;
+		rc = 0;
+	}
+	spin_unlock_irqrestore(&id->lock, flags);
+      out:
+	return rc;
+}
+
+/*
+ * functions for debug-views
+ ***********************************
+*/
+
+/*
+ * prints out actual debug level
+ */
+
+static int debug_prolog_level_fn(debug_info_t * id,
+				 struct debug_view *view, char *out_buf)
+{
+	int rc = 0;
+
+	if (out_buf == NULL) {
+		rc = 2;
+		goto out;
+	}
+	rc = sprintf(out_buf, "%i\n", id->level);
+      out:
+	return rc;
+}
+
+/*
+ * reads new debug level
+ */
+
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+				struct file *file, const char *user_buf,
+				size_t in_buf_size, loff_t * offset)
+{
+	char input_buf[1];
+	int rc = in_buf_size;
+
+	if (*offset != 0)
+		goto out;
+	if ((rc = copy_from_user(input_buf, user_buf, 1)))
+		goto out;
+	if (isdigit(input_buf[0])) {
+		int new_level = ((int) input_buf[0] - (int) '0');
+		if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+			printk(KERN_INFO
+			       "debug: level %i is out of range (%i - %i)\n",
+			       new_level, 0, DEBUG_MAX_LEVEL);
+		} else {
+			id->level = new_level;
+			printk(KERN_INFO
+			       "debug: set new level %i for %s\n",
+			       id->level, id->name);
+		}
+	} else {
+		printk(KERN_INFO "debug: level `%c` is not valid\n",
+		       input_buf[0]);
+	}
+      out:
+	*offset += in_buf_size;
+	return rc;		/* number of input characters */
+}
+
+/*
+ * prints debug data in hex format
+ */
+
+static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
+			       char *out_buf, const char *in_buf)
+{
+	int i, rc = 0;
+
+	if (out_buf == NULL || in_buf == NULL) {
+		rc = id->buf_size * 3;
+		goto out;
+	}
+	for (i = 0; i < id->buf_size; i++) {
+		rc += sprintf(out_buf + rc, "%02x ",
+			      ((unsigned char *) in_buf)[i]);
+	}
+      out:
+	return rc;
+}
+
+/*
+ * prints debug data in ascii format
+ */
+
+static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view, 
+				 char *out_buf, const char *in_buf)
 {
-  int rc = 0;
-  rc = debug_init ();
-  if (rc)
-    {
-      printk (KERN_INFO "An error occurred with debug_init\n");
-    }
-
-  {				/* test section */
-    debug_info_t *a[4];
-    printk (KERN_INFO "registering 1, %p\n", a[0] =
-	    debug_register ("debug1", 1, 1));
-    printk (KERN_INFO "registering 2, %p\n", a[1] =
-	    debug_register ("debug2", 1, 2));
-    printk (KERN_INFO "registering 3, %p\n", a[2] =
-	    debug_register ("debug3", 2, 1));
-    printk (KERN_INFO "registering 4, %p\n", a[3] =
-	    debug_register ("debug4", 2, 2));
-    debug_unregister (a[0], "debug1");
-    debug_unregister (a[1], "debug3");
-    printk (KERN_INFO "registering 1, %p\n", a[0] =
-	    debug_register ("debug5", 1, 1));
-    printk (KERN_INFO "registering 2, %p\n", a[1] =
-	    debug_register ("debug6", 1, 2));
-    debug_unregister (a[2], "debug2");
-    debug_unregister (a[3], "debug4");
-    debug_unregister (a[0], "debug5");
-    debug_unregister (a[1], "debug6");
-  }
-  return rc;
+	int i, rc = 0;
+
+	if (out_buf == NULL || in_buf == NULL) {
+		rc = id->buf_size;
+		goto out;
+	}
+	for (i = 0; i < id->buf_size; i++) {
+		unsigned char c = in_buf[i];
+		if (!isprint(c))
+			rc += sprintf(out_buf + rc, ".");
+		else
+			rc += sprintf(out_buf + rc, "%c", c);
+	}
+      out:
+	return rc;
 }
 
-void
-cleanup_module (void)
+/*
+ * prints debug data in ebcdic format
+ */
+
+static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view, 
+				  char *out_buf, const char *in_buf)
 {
+	int i, rc = 0;
 
-  return;
+	if (out_buf == NULL || in_buf == NULL) {
+		rc = id->buf_size;
+		goto out;
+	}
+	for (i = 0; i < id->buf_size; i++) {
+		unsigned char c = in_buf[i];
+		EBCASC(&c, 1);
+		if (!isprint(c))
+			rc += sprintf(out_buf + rc, ".");
+		else
+			rc += sprintf(out_buf + rc, "%c", c);
+	}
+      out:
+	return rc;
+}
+
+/*
+ * prints header for debug entry
+ */
+
+int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+			 int area, debug_entry_t * entry, char *out_buf)
+{
+	struct timeval time_val;
+	unsigned long long time;
+	char *except_str;
+	unsigned long caller;
+	int rc = 0;
+
+	if (out_buf == NULL) {
+		rc = DEBUG_PROC_HEADER_SIZE;
+		goto out;
+	}
+
+	time = entry->id.stck;
+	/* adjust todclock to 1970 */
+	time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+	tod_to_timeval(time, &time_val);
+
+	if (entry->id.fields.exception)
+		except_str = "*";
+	else
+		except_str = "-";
+	caller = (unsigned long) entry->caller;
+#if defined(CONFIG_ARCH_S390)
+	caller &= 0x7fffffff;
+	rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx  ",
+		      area, time_val.tv_sec,
+		      time_val.tv_usec, except_str,
+		      entry->id.fields.cpuid, caller);
+#endif
+      out:
+	return rc;
+}
+
+/*
+ * init_module:
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+	int rc = 0;
+#ifdef DEBUG
+	printk("debug_module_init: \n");
+#endif
+	rc = debug_init();
+	if (rc) 
+		printk(KERN_INFO "debug: an error occurred with debug_init\n");
+	return rc;
+}
+
+/*
+ * cleanup_module:
+ */
+
+void cleanup_module(void)
+{
+#ifdef DEBUG
+	printk("debug_cleanup_module: \n");
+#endif
+	debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
+	return;
 }
 
-#endif /* MODULE */
+#endif			/* MODULE */
diff -urN linux-2.2.18-pre20/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- linux-2.2.18-pre20/arch/s390/kernel/entry.S	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/entry.S	Mon Dec  3 22:14:16 2001
@@ -21,11 +21,11 @@
 
 /*
  * stack layout for the system_call stack entry
- * Martin please don't modify these back to hard coded values 
- * You know how bad I'm at mental arithmetic DJB & it gives 
+ * Martin please don't modify these back to hard coded values
+ * You know how bad I'm at mental arithmetic DJB & it gives
  * me grief when I modify the pt_regs
  */
-SP_PTREGS    =  STACK_FRAME_OVERHEAD 
+SP_PTREGS    =  STACK_FRAME_OVERHEAD
 SP_PSW       =  SP_PTREGS
 SP_R0        =  (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE)
 SP_R1        =  (SP_R0+GPR_SIZE)
@@ -51,13 +51,13 @@
 /* fpu registers are saved & restored by the gdb stub itself */
 SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
 SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not 
+/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not
  defined in ptrace.h but space is needed for this too */
 SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
 #else
 SP_PGM_OLD_ILC= (SP_TRAP+4)
 #endif
-SP_SVC_STEP   = (SP_PGM_OLD_ILC+4) 
+SP_SVC_STEP   = (SP_PGM_OLD_ILC+4)
 SP_SIZE      =  (SP_SVC_STEP+4)
 /*
  * these defines are offsets into the thread_struct
@@ -140,7 +140,7 @@
         stm     %r0,%r12,SP_R0(%r15)  ; /* store gprs 0-12 to kernel stack */ \
         st      %r2,SP_ORIG_R2(%r15)  ; /* store original content of gpr 2 */ \
         mvc     SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \
-        stam    %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \
+        stam    %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\
 	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \
         mvc     SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \
         la      %r0,psworg            ; /* store trap indication */ \
@@ -150,10 +150,10 @@
 #define RESTORE_ALL \
         mvc     __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
         lam     %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
-        lm      %r0,%r15,SP_R0(%r15)  ; /* load gprs 0-15 of user */ \
+        lm      %r0,%r15,SP_R0(%r15)      ; /* load gprs 0-15 of user */ \
         ni      __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \
         lpsw    __LC_RETURN_PSW             /* back to caller */
-	
+
 #define GET_CURRENT /* load pointer to task_struct to R9 */ \
 	lr      %r9,%r15 ;  \
 	n       %r9,BASED(.Lc0xffffe000)
@@ -170,12 +170,12 @@
 	basr    %r1,0                   # setup base pointer
 resume_base:
         l       %r4,_TSS_PTREGS(%r3)
-        tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
+        tm      SP_PSW-SP_PTREGS(%r4),0x40    # is the new process using per ?
         bz      resume_noper-resume_base(%r1) # if not we're fine
-        stctl   %r9,%r11,24(%r15)       # We are using per stuff
+        stctl   %r9,%r11,24(%r15)             # We are using per stuff
         clc     _TSS_PER(12,%r3),24(%r15)
         be      resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
-        lctl    %c9,%c11,_TSS_PER(%r3)  # Nope we didn't
+        lctl    %c9,%c11,_TSS_PER(%r3)        # Nope we didn't
 resume_noper:
         stm     %r6,%r15,24(%r15)       # store resume registers of prev task
         st      %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
@@ -248,7 +248,7 @@
 #
 # call do_signal before return
 #
-sysc_signal_return:     
+sysc_signal_return:
         la      %r2,SP_PTREGS(%r15) # load pt_regs
         sr      %r3,%r3           # clear *oldset
         l       %r1,BASED(.Ldo_signal)
@@ -276,7 +276,7 @@
 # call do_bottom_half and return from syscall, if interrupt-level
 # is zero
 #
-sysc_handle_bottom_half:        
+sysc_handle_bottom_half:
         l       %r1,BASED(.Ldo_bottom_half)
 	la      %r14,BASED(sysc_return_bh)
         br      %r1               # call do_bottom_half
@@ -284,7 +284,7 @@
 #
 # call schedule with sysc_return as return-address
 #
-sysc_reschedule:        
+sysc_reschedule:
         l       %r1,BASED(.Lschedule)
 	la      %r14,BASED(sysc_return)
         br      %r1               # call scheduler, return to sysc_return
@@ -293,7 +293,7 @@
 # a new process exits the kernel with ret_from_fork
 #
         .globl  ret_from_fork
-ret_from_fork:  
+ret_from_fork:
         basr    %r13,0
 	l       %r13,.Lentry_base-.(%r13)  # setup base pointer to &entry_base
         GET_CURRENT               # load pointer to task_struct to R9
@@ -314,23 +314,23 @@
 # but are called with different parameter.
 # return-address is set up above
 #
-sys_clone_glue: 
+sys_clone_glue:
         la      %r2,SP_PTREGS(%r15)    # load pt_regs
         l       %r1,BASED(.Lclone)
         br      %r1                   # branch to sys_clone
 
-sys_fork_glue:  
+sys_fork_glue:
         la      %r2,SP_PTREGS(%r15)    # load pt_regs
         l       %r1,BASED(.Lfork)
         br      %r1                   # branch to sys_fork
 
-sys_vfork_glue: 
+sys_vfork_glue:
         la      %r2,SP_PTREGS(%r15)    # load pt_regs
         l       %r1,BASED(.Lvfork)
         br      %r1                   # branch to sys_vfork
 
-sys_execve_glue:        
-        la      %r2,SP_PTREGS(%r15)    # load pt_regs
+sys_execve_glue:
+        la      %r2,SP_PTREGS(%r15)   # load pt_regs
         l       %r1,BASED(.Lexecve)
 	lr      %r12,%r14             # save return address
         basr    %r14,%r1              # call sys_execve
@@ -339,12 +339,12 @@
         b       4(%r12)               # SKIP ST 2,SP_R2(15) after BASR 14,8
                                       # in system_call/sysc_tracesys
 
-sys_sigreturn_glue:     
+sys_sigreturn_glue:
         la      %r2,SP_PTREGS(%r15)   # load pt_regs as parameter
         l       %r1,BASED(.Lsigreturn)
         br      %r1                   # branch to sys_sigreturn
 
-sys_rt_sigreturn_glue:     
+sys_rt_sigreturn_glue:
         la      %r2,SP_PTREGS(%r15)   # load pt_regs as parameter
         l       %r1,BASED(.Lrt_sigreturn)
         br      %r1                   # branch to sys_sigreturn
@@ -352,11 +352,11 @@
 #
 # sigsuspend and rt_sigsuspend need pt_regs as an additional
 # parameter and they have to skip the store of %r2 into the
-# user register %r2 because the return value was set in 
+# user register %r2 because the return value was set in
 # sigsuspend and rt_sigsuspend already and must not be overwritten!
 #
 
-sys_sigsuspend_glue:    
+sys_sigsuspend_glue:
         lr      %r5,%r4               # move mask back
         lr      %r4,%r3               # move history1 parameter
         lr      %r3,%r2               # move history0 parameter
@@ -365,7 +365,7 @@
 	la      %r14,4(%r14)          # skip store of return value
         br      %r1                   # branch to sys_sigsuspend
 
-sys_rt_sigsuspend_glue: 
+sys_rt_sigsuspend_glue:
         lr      %r4,%r3               # move sigsetsize parameter
         lr      %r3,%r2               # move unewset parameter
         la      %r2,SP_PTREGS(%r15)   # load pt_regs as first parameter
@@ -373,6 +373,12 @@
 	la      %r14,4(%r14)          # skip store of return value
         br      %r1                   # branch to sys_rt_sigsuspend
 
+sys_sigaltstack_glue:
+        la      %r4,SP_PTREGS(%r15)   # load pt_regs as parameter
+        l       %r1,BASED(.Lsigaltstack)
+        br      %r1                   # branch to sys_sigreturn
+
+
 	.globl  sys_call_table	
 sys_call_table:
         .long  sys_ni_syscall            /* 0 */
@@ -561,13 +567,13 @@
         .long  sys_getcwd
         .long  sys_capget
         .long  sys_capset                /* 185 */
-        .long  sys_sigaltstack
+        .long  sys_sigaltstack_glue
         .long  sys_sendfile
         .long  sys_ni_syscall            /* streams1 */
         .long  sys_ni_syscall            /* streams2 */
         .long  sys_vfork_glue            /* 190 */
 	.rept  255-190
-        .long  sys_ni_syscall
+	.long  sys_ni_syscall
 	.endr
 
 /*
@@ -603,7 +609,7 @@
         be      BASED(pgm_svcper)
 # no interesting special case, ignore PER event
         lm      %r13,%r15,__LC_SAVE_AREA
-        lpsw    0x28
+	lpsw    0x28
 # it was a single stepped SVC that is causing all the trouble
 pgm_svcper:
         tm      0x21,0x01                # test problem state bit
@@ -622,7 +628,7 @@
         la      %r0,0x20                 # store trap indication
         st      %r0,SP_TRAP(%r15)
         xc      0(4,%r15),0(%r15)        # clear back chain
-	mvi     SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
+	mvi     SP_SVC_STEP(%r15),1      # make SP_SVC_STEP nonzero
 	mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information	
         b       BASED(pgm_system_call)   # now do the svc
 pgm_svcret:
@@ -723,7 +729,7 @@
 # call do_bottom_half and return from syscall, if interrupt-level
 # is zero
 #
-io_handle_bottom_half:        
+io_handle_bottom_half:
         l       %r1,BASED(.Ldo_bottom_half)
 	la      %r14,BASED(io_return_bh)
         br      %r1               # call do_bottom_half
@@ -731,7 +737,7 @@
 #
 # call schedule with io_return as return-address
 #
-io_reschedule:        
+io_reschedule:
         l       %r1,BASED(.Lschedule)
 	la      %r14,BASED(io_return)
         br      %r1               # call scheduler, return to io_return
@@ -739,7 +745,7 @@
 #
 # call do_signal before return
 #
-io_signal_return:     
+io_signal_return:
         la      %r2,SP_PTREGS(%r15) # load pt_regs
         sr      %r3,%r3           # clear *oldset
         l       %r1,BASED(.Ldo_signal)
@@ -755,9 +761,7 @@
         SAVE_ALL(0x18)
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
         lh      %r3,__LC_EXT_INT_CODE  # error code
-        lr      %r1,%r3                # calculate index
-        srl     %r1,8                  #  = (code + (code >> 8)) & 0xff
-        alr     %r1,%r3
+        lr      %r1,%r3                # calculate index = code & 0xff
         n       %r1,BASED(.Lc0xff)
         sll     %r1,2
 	l       %r9,BASED(.Lext_hash)
@@ -773,7 +777,7 @@
 ext_int_found:
         l       %r9,4(%r9)             # get handler address
         la      %r14,BASED(io_return)
-	br      %r9               # branch to ext call handler
+        br      %r9                    # branch to ext call handler
 
 /*
  * Machine check handler routines
@@ -857,6 +861,7 @@
 .Lrt_sigreturn:.long  sys_rt_sigreturn
 .Lrt_sigsuspend:
 	       .long  sys_rt_sigsuspend
+.Lsigaltstack: .long  sys_sigaltstack
 .Lsigreturn:   .long  sys_sigreturn
 .Lsigsuspend:  .long  sys_sigsuspend
 .Ltrace:       .long  syscall_trace
diff -urN linux-2.2.18-pre20/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- linux-2.2.18-pre20/arch/s390/kernel/head.S	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/head.S	Mon Dec  3 22:14:16 2001
@@ -528,21 +528,21 @@
         lpsw  .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
         .align 8
-.Lentry:.long  0x04080000,0x80000000 + _stext
+.Lentry:.long  0x00080000,0x80000000 + _stext
 .Lctl:  .long  0x04b50002               # cr0: various things
-        .long  .Lpgd+0x7f               # cr1: primary space segment table
+        .long  0                        # cr1: primary space segment table
         .long  0                        # cr2: access register translation
         .long  0                        # cr3: instruction authorization
         .long  0                        # cr4: instruction authorization
         .long  0                        # cr5:  various things
         .long  0                        # cr6:  I/O interrupts
-        .long  .Lpgd+0x7f               # cr7:  secondary space segment table
+        .long  0                        # cr7:  secondary space segment table
         .long  0                        # cr8:  access registers translation
         .long  0                        # cr9:  tracing off
         .long  0                        # cr10: tracing off
         .long  0                        # cr11: tracing off
         .long  0                        # cr12: tracing off
-        .long  .Lpgd+0x7f               # cr13: home space segment table
+        .long  0                        # cr13: home space segment table
         .long  0xc0000000               # cr14: machine check handling off
         .long  0                        # cr15: linkage stack operations
 .Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
@@ -630,43 +630,4 @@
 	    .align 8
 .Ldw:	    .long  0x000a0000,0x00000000
 
-#
-#        tempory segment-table at 0x11000
-#
-        .org   0x11000
-.Lpgd:  .long  .Lpt0+0x1f               # 00000000-000fffff
-        .long  .Lpt1+0x1f               # 00100000-001fffff
-        .long  .Lpt2+0x1f               # 00200000-002fffff
-        .long  .Lpt3+0x1f               # 00300000-003fffff
-        .fill  2044,4,0x20              # 00400000-7fffffff
-
-#
-#        tempory page-tables at 0x12000-0x15fff
-#
-        .macro  mktable from,to
-        .long   \from*0x10000
-        .long   \from*0x10000+0x1000
-        .long   \from*0x10000+0x2000
-        .long   \from*0x10000+0x3000
-        .long   \from*0x10000+0x4000
-        .long   \from*0x10000+0x5000
-        .long   \from*0x10000+0x6000
-        .long   \from*0x10000+0x7000
-        .long   \from*0x10000+0x8000
-        .long   \from*0x10000+0x9000
-        .long   \from*0x10000+0xa000
-        .long   \from*0x10000+0xb000
-        .long   \from*0x10000+0xc000
-        .long   \from*0x10000+0xd000
-        .long   \from*0x10000+0xe000
-        .long   \from*0x10000+0xf000
-        .if     \to-\from
-        mktable "(\from+1)",\to
-        .endif
-        .endm
-
-.Lpt0:  mktable 0,15
-.Lpt1:  mktable 16,31
-.Lpt2:  mktable 32,47
-.Lpt3:  mktable 48,63
 
diff -urN linux-2.2.18-pre20/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c
--- linux-2.2.18-pre20/arch/s390/kernel/irq.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/irq.c	Mon Dec  3 22:14:16 2001
@@ -36,13 +36,13 @@
 #include <asm/delay.h>
 #include <asm/lowcore.h>
 
-unsigned long s390_init_IRQ(unsigned long);
-void s390_free_irq(unsigned int irq, void *dev_id);
-int  s390_request_irq( unsigned int   irq,
-                       void           (*handler)(int, void *, struct pt_regs *),
-                       unsigned long  irqflags,
-                       const char    *devname,
-                       void          *dev_id);
+unsigned long s390_init_IRQ   ( unsigned long);
+void          s390_free_irq   ( unsigned int irq, void *dev_id);
+int           s390_request_irq( unsigned int irq,
+                     void           (*handler)(int, void *, struct pt_regs *),
+                     unsigned long  irqflags,
+                     const char    *devname,
+                     void          *dev_id);
 
 atomic_t nmi_counter;
 
@@ -82,7 +82,7 @@
 
 		action = ioinfo[i]->irq_desc.action;
 		
-		if (!action)
+  		if (!action)
 			continue;
 
 		p += sprintf(p, "%3d: ",i);
@@ -90,8 +90,8 @@
 		p += sprintf(p, "%10u ", kstat_irqs(i));
 #else
 		for (j=0; j<smp_num_cpus; j++)
-			p += sprintf(p, "%10u ",
-				     kstat.irqs[cpu_logical_map(j)][i]);
+			p += sprintf( p, "%10u ",
+			              kstat.irqs[cpu_logical_map(j)][i]);
 #endif
 		p += sprintf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
 		p += sprintf(p, "  %s", action->name);
@@ -403,13 +403,16 @@
 
 __initfunc(unsigned long init_IRQ( unsigned long memory))
 {
-	return s390_init_IRQ( memory);
+	int result;
+
+	result=s390_init_IRQ(memory);
+	return result;
 }
 
 
 void free_irq(unsigned int irq, void *dev_id)
 {
-	s390_free_irq( irq, dev_id);
+   s390_free_irq( irq, dev_id);
 }
 
 
@@ -419,7 +422,7 @@
                  const char    *devname,
                  void          *dev_id)
 {
-	return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
+   return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
 
 }
 
diff -urN linux-2.2.18-pre20/arch/s390/kernel/mathemu.c linux/arch/s390/kernel/mathemu.c
--- linux-2.2.18-pre20/arch/s390/kernel/mathemu.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/mathemu.c	Mon Dec  3 22:14:16 2001
@@ -16,20 +16,61 @@
 
 #include <asm/uaccess.h>
 #include <asm/mathemu.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+#define mathemu_put_user(x, ptr) \
+{                                \
+	if(put_user((x),(ptr)))  \
+		return 1;        \
+}
+
+#define mathemu_get_user(x, ptr) \
+{                                \
+	if(get_user((x),(ptr)))  \
+		return 1;        \
+}
+
+
+#define mathemu_copy_from_user(to,from,n)                 \
+{                                                         \
+	if(copy_from_user((to),(from),(n))==-EFAULT)      \
+		return 1;                                 \
+}
+
+
+#define mathemu_copy_to_user(to, from, n)                 \
+{                                                         \
+	if(copy_to_user((to),(from),(n))==-EFAULT)      \
+		return 1;                                 \
+}
+
+
 
 static void display_emulation_not_implemented(char *instr)
 {
-	struct pt_regs *regs=current->tss.regs;
-	printk("%s not implemented\n",instr);
-	printk("Process with %s instruction %s (pid: %d, stackpage=%08X)\n",
-	       instr,
-                current->comm, current->pid, 4096+(addr_t)current);
-	printk("%s's PSW:    %08lx %08lx\n",instr,
-                (unsigned long) regs->psw.mask,
-                (unsigned long) regs->psw.addr);
+	struct pt_regs *regs;
+	__u16 *location;
+	
+#if CONFIG_SYSCTL
+	if(sysctl_ieee_emulation_warnings)
+#endif
+	{
+		regs=current->tss.regs;
+		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+		printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
+		       instr,
+		       current->comm, current->pid);
+		printk("%s's PSW:    %08lx %08lx\n",instr,
+		       (unsigned long) regs->psw.mask,
+		       (unsigned long) location);
+	}
 }
 
-static void set_CC_df(__u64 val1,__u64 val2) {
+static int set_CC_df(__u64 val1,__u64 val2) {
         int rc;
         rc = __cmpdf2(val1,val2);
         current->tss.regs->psw.mask &= 0xFFFFCFFF;
@@ -41,9 +82,10 @@
                         current->tss.regs->psw.mask |= 0x00002000;
                         break;
         }
+	return 0;
 }
 
-static void set_CC_sf(__u32 val1,__u32 val2) {
+static int set_CC_sf(__u32 val1,__u32 val2) {
         int rc;
         rc = __cmpsf2(val1,val2);
         current->tss.regs->psw.mask &= 0xFFFFCFFF;
@@ -55,384 +97,473 @@
                         current->tss.regs->psw.mask |= 0x00002000;
                         break;
         }
+	return 0;
 }
 
 
-static void emu_adb (int rx, __u64 val) {
+static int emu_adb (int rx, __u64 val) {
         current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,val);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_adbr (int rx, int ry) {
+static int emu_adbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,
                                          current->tss.fp_regs.fprs[ry].d);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_aeb (int rx, __u32 val) {
+static int emu_aeb (int rx, __u32 val) {
         current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,val);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_aebr (int rx, int ry) {
+static int emu_aebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,
                                         current->tss.fp_regs.fprs[ry].f);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_axbr (int rx, int ry) {
+static int emu_axbr (int rx, int ry) {
         display_emulation_not_implemented("axbr");
+	return 0;
 }
 
-static void emu_cdb (int rx, __u64 val) {
+static int emu_cdb (int rx, __u64 val) {
         set_CC_df(current->tss.fp_regs.fprs[rx].d,val);
+	return 0;
 }
 
-static void emu_cdbr (int rx, int ry) {
+static int emu_cdbr (int rx, int ry) {
         set_CC_df(current->tss.fp_regs.fprs[rx].d,current->tss.fp_regs.fprs[ry].d);
+	return 0;
 }
 
-static void emu_cdfbr (int rx, int ry) {
+static int emu_cdfbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d =
                      __floatsidf(current->tss.regs->gprs[ry]);
+	return 0;
 }
 
-static void emu_ceb (int rx, __u32 val) {
+static int emu_ceb (int rx, __u32 val) {
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,val);
+	return 0;
 }
 
-static void emu_cebr (int rx, int ry) {
+static int emu_cebr (int rx, int ry) {
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,current->tss.fp_regs.fprs[ry].f);
+	return 0;
 }
 
-static void emu_cefbr (int rx, int ry) {
+static int emu_cefbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f =
                      __floatsisf(current->tss.regs->gprs[ry]);
+	return 0;
 }
 
-static void emu_cfdbr (int rx, int ry, int mask) {
+static int emu_cfdbr (int rx, int ry, int mask) {
         current->tss.regs->gprs[rx] =
                      __fixdfsi(current->tss.fp_regs.fprs[ry].d);
+	return 0;
 }
 
-static void emu_cfebr (int rx, int ry, int mask) {
+static int emu_cfebr (int rx, int ry, int mask) {
         current->tss.regs->gprs[rx] =
                      __fixsfsi(current->tss.fp_regs.fprs[ry].f);
+	return 0;
 }
 
-static void emu_cfxbr (int rx, int ry, int mask) {
+static int emu_cfxbr (int rx, int ry, int mask) {
         display_emulation_not_implemented("cfxbr");
+	return 0;
 }
 
-static void emu_cxbr (int rx, int ry) {
+static int emu_cxbr (int rx, int ry) {
         display_emulation_not_implemented("cxbr");
+	return 0;
 }
 
-static void emu_cxfbr (int rx, int ry) {
+static int emu_cxfbr (int rx, int ry) {
         display_emulation_not_implemented("cxfbr");
+	return 0;
 }
 
-static void emu_ddb (int rx, __u64 val) {
+static int emu_ddb (int rx, __u64 val) {
         current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,val);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_ddbr (int rx, int ry) {
+static int emu_ddbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,
                                          current->tss.fp_regs.fprs[ry].d);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_deb (int rx, __u32 val) {
+static int emu_deb (int rx, __u32 val) {
         current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,val);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_debr (int rx, int ry) {
+static int emu_debr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,
                                          current->tss.fp_regs.fprs[ry].f);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_didbr (int rx, int ry, int mask) {
+static int emu_didbr (int rx, int ry, int mask) {
         display_emulation_not_implemented("didbr");
+	return 0;
 }
 
-static void emu_diebr (int rx, int ry, int mask) {
+static int emu_diebr (int rx, int ry, int mask) {
         display_emulation_not_implemented("diebr");
+	return 0;
 }
 
-static void emu_dxbr (int rx, int ry) {
+static int emu_dxbr (int rx, int ry) {
         display_emulation_not_implemented("dxbr");
+	return 0;
 }
 
-static void emu_efpc (int rx, int ry) {
-        display_emulation_not_implemented("efpc");
+static int emu_efpc (int rx, int ry) {
+	current->tss.regs->gprs[rx]=current->tss.fp_regs.fpc;
+	return 0;
 }
 
-static void emu_fidbr (int rx, int ry, int mask) {
+static int emu_fidbr (int rx, int ry, int mask) {
         display_emulation_not_implemented("fidbr");
+	return 0;
 }
 
-static void emu_fiebr (int rx, int ry, int mask) {
+static int emu_fiebr (int rx, int ry, int mask) {
         display_emulation_not_implemented("fiebr");
+	return 0;
 }
 
-static void emu_fixbr (int rx, int ry, int mask) {
+static int emu_fixbr (int rx, int ry, int mask) {
         display_emulation_not_implemented("fixbr");
+	return 0;
 }
 
-static void emu_kdb (int rx, __u64 val) {
+static int emu_kdb (int rx, __u64 val) {
         display_emulation_not_implemented("kdb");
+	return 0;
 }
 
-static void emu_kdbr (int rx, int ry) {
+static int emu_kdbr (int rx, int ry) {
         display_emulation_not_implemented("kdbr");
+	return 0;
 }
 
-static void emu_keb (int rx, __u32 val) {
+static int emu_keb (int rx, __u32 val) {
         display_emulation_not_implemented("keb");
+	return 0;
 }
 
-static void emu_kebr (int rx, int ry) {
+static int emu_kebr (int rx, int ry) {
         display_emulation_not_implemented("kebr");
+	return 0;
 }
 
-static void emu_kxbr (int rx, int ry) {
+static int emu_kxbr (int rx, int ry) {
         display_emulation_not_implemented("kxbr");
+	return 0;
 }
 
-static void emu_lcdbr (int rx, int ry) {
+static int emu_lcdbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d =
         __negdf2(current->tss.fp_regs.fprs[ry].d);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_lcebr (int rx, int ry) {
+static int emu_lcebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f =
         __negsf2(current->tss.fp_regs.fprs[ry].f);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_lcxbr (int rx, int ry) {
+static int emu_lcxbr (int rx, int ry) {
         display_emulation_not_implemented("lcxbr");
+	return 0;
 }
 
-static void emu_ldeb (int rx, __u32 val) {
+static int emu_ldeb (int rx, __u32 val) {
         current->tss.fp_regs.fprs[rx].d = __extendsfdf2(val);
+	return 0;
 }
 
-static void emu_ldebr (int rx, int ry) {
+static int emu_ldebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d =
         __extendsfdf2(current->tss.fp_regs.fprs[ry].f);
+	return 0;
 }
 
-static void emu_ldxbr (int rx, int ry) {
+static int emu_ldxbr (int rx, int ry) {
         display_emulation_not_implemented("ldxbr");
+	return 0;
 }
 
-static void emu_ledbr (int rx, int ry) {
+static int emu_ledbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = __truncdfsf2(current->tss.fp_regs.fprs[ry].d);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_lexbr (int rx, int ry) {
+static int emu_lexbr (int rx, int ry) {
         display_emulation_not_implemented("lexbr");
+	return 0;
 }
 
-static void emu_lndbr (int rx, int ry) {
+static int emu_lndbr (int rx, int ry) {
         display_emulation_not_implemented("lndbr");
+	return 0;
 }
 
-static void emu_lnebr (int rx, int ry) {
+static int emu_lnebr (int rx, int ry) {
         display_emulation_not_implemented("lnebr");
+	return 0;
 }
 
-static void emu_lnxbr (int rx, int ry) {
+static int emu_lnxbr (int rx, int ry) {
         display_emulation_not_implemented("lnxbr");
+	return 0;
 }
 
-static void emu_lpdbr (int rx, int ry) {
+static int emu_lpdbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d = __absdf2(current->tss.fp_regs.fprs[ry].d);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0);
+	return 0;
 }
 
-static void emu_lpebr (int rx, int ry) {
+static int emu_lpebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = __abssf2(current->tss.fp_regs.fprs[ry].f);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_lpxbr (int rx, int ry) {
+static int emu_lpxbr (int rx, int ry) {
         display_emulation_not_implemented("lpxbr");
+	return 0;
 }
 
-static void emu_ltdbr (int rx, int ry) {
+static int emu_ltdbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d = current->tss.fp_regs.fprs[ry].d;
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_ltebr (int rx, int ry) {
+static int emu_ltebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = current->tss.fp_regs.fprs[ry].f;
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_ltxbr (int rx, int ry) {
+static int emu_ltxbr (int rx, int ry) {
         display_emulation_not_implemented("ltxbr");
+	return 0;
 }
 
-static void emu_lxdb (int rx, __u64 val) {
+static int emu_lxdb (int rx, __u64 val) {
         display_emulation_not_implemented("lxdb");
+	return 0;
 }
 
-static void emu_lxdbr (int rx, int ry) {
+static int emu_lxdbr (int rx, int ry) {
         display_emulation_not_implemented("lxdbr");
+	return 0;
 }
 
-static void emu_lxeb (int rx, __u32 val) {
+static int emu_lxeb (int rx, __u32 val) {
         display_emulation_not_implemented("lxeb");
+	return 0;
 }
 
-static void emu_lxebr (int rx, int ry) {
+static int emu_lxebr (int rx, int ry) {
         display_emulation_not_implemented("lxebr");
+	return 0;
 }
 
-static void emu_madb (int rx, __u64 val, int mask) {
+static int emu_madb (int rx, __u64 val, int mask) {
         display_emulation_not_implemented("madb");
+	return 0;
 }
 
-static void emu_madbr (int rx, int ry, int mask) {
+static int emu_madbr (int rx, int ry, int mask) {
         display_emulation_not_implemented("madbr");
+	return 0;
 }
 
-static void emu_maeb (int rx, __u32 val, int mask) {
+static int emu_maeb (int rx, __u32 val, int mask) {
         display_emulation_not_implemented("maeb");
+	return 0;
 }
 
-static void emu_maebr (int rx, int ry, int mask) {
+static int emu_maebr (int rx, int ry, int mask) {
         display_emulation_not_implemented("maebr");
+	return 0;
 }
 
-static void emu_mdb (int rx, __u64 val) {
+static int emu_mdb (int rx, __u64 val) {
         current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,val);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_mdbr (int rx, int ry) {
+static int emu_mdbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,
                                          current->tss.fp_regs.fprs[ry].d);
         set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_mdeb (int rx, __u32 val) {
+static int emu_mdeb (int rx, __u32 val) {
         display_emulation_not_implemented("mdeb");
+	return 0;
 }
 
-static void emu_mdebr (int rx, int ry) {
+static int emu_mdebr (int rx, int ry) {
         display_emulation_not_implemented("mdebr");
+	return 0;
 }
 
-static void emu_meeb (int rx, __u32 val) {
+static int emu_meeb (int rx, __u32 val) {
         current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f,
                                          val);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_meebr (int rx, int ry) {
+static int emu_meebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f,
                                          current->tss.fp_regs.fprs[ry].f);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_msdb (int rx, __u64 val, int mask) {
+static int emu_msdb (int rx, __u64 val, int mask) {
         display_emulation_not_implemented("msdb");
+	return 0;
 }
 
-static void emu_msdbr (int rx, int ry, int mask) {
+static int emu_msdbr (int rx, int ry, int mask) {
         display_emulation_not_implemented("msdbr");
+	return 0;
 }
 
-static void emu_mseb (int rx, __u32 val, int mask) {
+static int emu_mseb (int rx, __u32 val, int mask) {
         display_emulation_not_implemented("mseb");
+	return 0;
 }
 
-static void emu_msebr (int rx, int ry, int mask) {
+static int emu_msebr (int rx, int ry, int mask) {
         display_emulation_not_implemented("msebr");
+	return 0;
 }
 
-static void emu_mxbr (int rx, int ry) {
+static int emu_mxbr (int rx, int ry) {
         display_emulation_not_implemented("mxbr");
+	return 0;
 }
 
-static void emu_mxdb (int rx, __u64 val) {
+static int emu_mxdb (int rx, __u64 val) {
         display_emulation_not_implemented("mxdb");
+	return 0;
 }
 
-static void emu_mxdbr (int rx, int ry) {
+static int emu_mxdbr (int rx, int ry) {
         display_emulation_not_implemented("mxdbr");
+	return 0;
 }
 
-static void emu_sdb (int rx, __u64 val) {
+static int emu_sdb (int rx, __u64 val) {
         current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d,
                                          val);
         set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_sdbr (int rx, int ry) {
+static int emu_sdbr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d,
                                          current->tss.fp_regs.fprs[ry].d);
         set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL);
+	return 0;
 }
 
-static void emu_seb (int rx, __u32 val) {
+static int emu_seb (int rx, __u32 val) {
         current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f,
                                          val);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_sebr (int rx, int ry) {
+static int emu_sebr (int rx, int ry) {
         current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f,
                                          current->tss.fp_regs.fprs[ry].f);
         set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+	return 0;
 }
 
-static void emu_sfpc (int rx, int ry) {
-        display_emulation_not_implemented("sfpc");
+static int emu_sfpc (int rx, int ry) {
+	__u32 val=current->tss.regs->gprs[rx];
+	if(val==0)
+		current->tss.fp_regs.fpc=val;
+	else
+		display_emulation_not_implemented("sfpc");
+	return 0;
 }
 
-static void emu_sqdb (int rx, __u64 val) {
+static int emu_sqdb (int rx, __u64 val) {
         display_emulation_not_implemented("sqdb");
+	return 0;
 }
 
-static void emu_sqdbr (int rx, int ry) {
+static int emu_sqdbr (int rx, int ry) {
         display_emulation_not_implemented("sqdbr");
+	return 0;
 }
 
-static void emu_sqeb (int rx, __u32 val) {
+static int emu_sqeb (int rx, __u32 val) {
         display_emulation_not_implemented("sqeb");
+	return 0;
 }
 
-static void emu_sqebr (int rx, int ry) {
+static int emu_sqebr (int rx, int ry) {
         display_emulation_not_implemented("sqebr");
+	return 0;
 }
 
-static void emu_sqxbr (int rx, int ry) {
+static int emu_sqxbr (int rx, int ry) {
         display_emulation_not_implemented("sqxbr");
+	return 0;
 }
 
-static void emu_sxbr (int rx, int ry) {
+static int emu_sxbr (int rx, int ry) {
         display_emulation_not_implemented("sxbr");
+	return 0;
 }
 
-static void emu_tcdb (int rx, __u64 val) {
+static int emu_tcdb (int rx, __u64 val) {
         display_emulation_not_implemented("tcdb");
+	return 0;
 }
 
-static void emu_tceb (int rx, __u32 val) {
+static int emu_tceb (int rx, __u32 val) {
         display_emulation_not_implemented("tceb");
+	return 0;
 }
 
-static void emu_tcxb (int rx, __u64 val) {
+static int emu_tcxb (int rx, __u64 val) {
         display_emulation_not_implemented("tcxb");
+	return 0;
 }
 
 
@@ -486,6 +617,7 @@
 }
 
 int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+	int rc=0;
         static const __u8 format_table[] = {
                 2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
                 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
@@ -551,84 +683,82 @@
                 emu_store_regd((opcode[3]>>4)&15);
                 emu_store_regd(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15);
-                emu_load_regd((opcode[3]>>4)&15);
-                emu_load_regd(opcode[3]&15);
-                return 0;
+		emu_load_regd((opcode[3]>>4)&15);
+		emu_load_regd(opcode[3]&15);
+                return rc;
         case 2: /* RRE format, float operation */
                 emu_store_rege((opcode[3]>>4)&15);
                 emu_store_rege(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15);
-                emu_load_rege((opcode[3]>>4)&15);
-                emu_load_rege(opcode[3]&15);
-                return 0;
+		emu_load_rege((opcode[3]>>4)&15);
+		emu_load_rege(opcode[3]&15);
+                return rc;
         case 3: /* RRF format, double operation */
                 emu_store_regd((opcode[3]>>4)&15);
                 emu_store_regd(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                emu_load_regd((opcode[3]>>4)&15);
-                emu_load_regd(opcode[3]&15);
-                return 0;
+		emu_load_regd((opcode[3]>>4)&15);
+		emu_load_regd(opcode[3]&15);
+		return rc;
         case 4: /* RRF format, float operation */
                 emu_store_rege((opcode[3]>>4)&15);
                 emu_store_rege(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                emu_load_rege((opcode[3]>>4)&15);
-                emu_load_rege(opcode[3]&15);
-                return 0;
+		emu_load_rege((opcode[3]>>4)&15);
+		emu_load_rege(opcode[3]&15);
+                return rc;
         case 5: /* RRE format, cefbr instruction */
                 emu_store_rege((opcode[3]>>4)&15);
                 /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15);
-                emu_load_rege((opcode[3]>>4)&15);
-                return 0;
+		emu_load_rege((opcode[3]>>4)&15);
+                return rc;
         case 6: /* RRE format, cdfbr & cxfbr instruction */
                 emu_store_regd((opcode[3]>>4)&15);
                 /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15);
-                emu_load_regd((opcode[3]>>4)&15);
-                return 0;
-                /* FIXME !! */
-                return 0;
-        case 7: /* RRF format, cfebr instruction */
+		emu_load_regd((opcode[3]>>4)&15);
+                return rc;
+	case 7: /* RRF format, cfebr instruction */
                 emu_store_rege(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                return 0;
+                return rc;
         case 8: /* RRF format, cfdbr & cfxbr instruction */
                 emu_store_regd(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
-                return 0;
+                return rc;
 	case 9: /* RRE format, ldebr & mdebr instruction */
 		/* float store but double load */
                 emu_store_rege((opcode[3]>>4)&15);
                 emu_store_rege(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15);
-                emu_load_regd((opcode[3]>>4)&15);
-                return 0;
+		emu_load_regd((opcode[3]>>4)&15);
+                return rc;
         case 10: /* RRE format, ledbr instruction */
 		/* double store but float load */
                 emu_store_regd((opcode[3]>>4)&15);
                 emu_store_regd(opcode[3]&15);
                 /* call the emulation function */
-                ((void (*)(int, int))jump_table[opcode[1]])
+                rc=((int (*)(int, int))jump_table[opcode[1]])
                         (opcode[3]>>4,opcode[3]&15);
-                emu_load_rege((opcode[3]>>4)&15);
-                return 0;
+		emu_load_rege((opcode[3]>>4)&15);
+                return rc;
         default:
                 return 1;
         }
@@ -645,6 +775,8 @@
 }
     
 int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+	int rc=0;
+
         static const __u8 format_table[] = {
                 0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
                 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
@@ -682,13 +814,12 @@
                 emu_store_regd((opcode[1]>>4)&15);
                 opc = *((__u32 *) opcode);
                 dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if copy_from_user fails ? */
-                copy_from_user(&temp, dxb, 8);
+                mathemu_copy_from_user(&temp, dxb, 8);
                 /* call the emulation function */
-                ((void (*)(int, __u64))jump_table[opcode[5]])
+                rc=((int (*)(int, __u64))jump_table[opcode[5]])
                         (opcode[1]>>4,temp);
-                emu_load_regd((opcode[1]>>4)&15);
-                return 0;
+		emu_load_regd((opcode[1]>>4)&15);
+                return rc;
         }
         case 2: /* RXE format, __u32 constant */ {
                 __u32 *dxb, temp;
@@ -697,13 +828,12 @@
                 emu_store_rege((opcode[1]>>4)&15);
                 opc = *((__u32 *) opcode);
                 dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if get_user fails ? */
-                get_user(temp, dxb);
+                mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                ((void (*)(int, __u32))jump_table[opcode[5]])
+                rc=((int (*)(int, __u32))jump_table[opcode[5]])
                         (opcode[1]>>4,temp);
-                emu_load_rege((opcode[1]>>4)&15);
-                return 0;
+		emu_load_rege((opcode[1]>>4)&15);
+                return rc;
         }
         case 3: /* RXF format, __u64 constant */ {
                 __u32 *dxb, temp;
@@ -712,13 +842,12 @@
                 emu_store_regd((opcode[1]>>4)&15);
                 opc = *((__u32 *) opcode);
                 dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if copy_from_user fails ? */
-                copy_from_user(&temp, dxb, 8);
+                 mathemu_copy_from_user(&temp, dxb, 8);
                 /* call the emulation function */
-                ((void (*)(int, __u32, int))jump_table[opcode[5]])
+                rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
                         (opcode[1]>>4,temp,opcode[4]>>4);
-                emu_load_regd((opcode[1]>>4)&15);
-                return 0;
+		emu_load_regd((opcode[1]>>4)&15);
+                return rc;
         }
         case 4: /* RXF format, __u32 constant */ {
                 __u32 *dxb, temp;
@@ -727,29 +856,27 @@
                 emu_store_rege((opcode[1]>>4)&15);
                 opc = *((__u32 *) opcode);
                 dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if get_user fails ? */
-                get_user(temp, dxb);
+                mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                ((void (*)(int, __u32, int))jump_table[opcode[5]])
+                rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
                         (opcode[1]>>4,temp,opcode[4]>>4);
                 emu_load_rege((opcode[1]>>4)&15);
-                return 0;
+                return rc;
         }
 	case 5: /* RXE format, __u32 constant */
                 /* store_rege and load_regd */ 
-		{
+	{
                 __u32 *dxb, temp;
                 __u32 opc;
                 emu_store_rege((opcode[1]>>4)&15);
                 opc = *((__u32 *) opcode);
                 dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-                /* FIXME: how to react if get_user fails ? */
-                get_user(temp, dxb);
+                mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                ((void (*)(int, __u32))jump_table[opcode[5]])
+                rc=((int (*)(int, __u32))jump_table[opcode[5]])
                         (opcode[1]>>4,temp);
                 emu_load_regd((opcode[1]>>4)&15);
-                return 0;
+                return rc;
         }
         default:
                 return 1;
@@ -759,7 +886,7 @@
 /*
  * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
  */
-void math_emu_ldr(__u8 *opcode) {
+int math_emu_ldr(__u8 *opcode) {
         __u16 opc = *((__u16 *) opcode);
 
         if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
@@ -785,12 +912,13 @@
                 current->tss.fp_regs.fprs[(opc&0x00f0)>>4] =
                         current->tss.fp_regs.fprs[opc&0x000f];
         }
+	return 0;
 }
 
 /*
  * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
  */
-void math_emu_ler(__u8 *opcode) {
+int math_emu_ler(__u8 *opcode) {
         __u16 opc = *((__u16 *) opcode);
 
         if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
@@ -816,61 +944,68 @@
                 current->tss.fp_regs.fprs[(opc&0x00f0)>>4] =
                         current->tss.fp_regs.fprs[opc&0x000f];
         }
+	return 0;
 }
 
 /*
  * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
  */
-void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
         __u32 opc = *((__u32 *) opcode);
         __u64 *dxb;
 
         dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if copy_from_user fails ? */
-        copy_from_user(&current->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+        mathemu_copy_from_user(&current->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+	return 0;
 }
 
 /*
  * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
  */
-void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
         __u32 opc = *((__u32 *) opcode);
         __u32 *mem, *dxb;
 
         dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if get_user fails ? */
         mem = (__u32 *) (&current->tss.fp_regs.fprs[(opc>>20)&15].f);
-        get_user(mem[0], dxb);
+        mathemu_get_user(mem[0], dxb);
+	return 0;
 }
 
 /*
  * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
  */
-void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
         __u32 opc = *((__u32 *) opcode);
         __u64 *dxb;
         dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if copy_to_user fails ? */
-        copy_to_user(dxb, &current->tss.fp_regs.fprs[(opc>>20)&15].d, 8);
+        mathemu_copy_to_user(dxb, &current->tss.fp_regs.fprs[(opc>>20)&15].d, 8);
+	return 0;
 }
 
 /*
  * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
  */
-void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
         __u32 opc = *((__u32 *) opcode);
         __u32 *mem, *dxb;
         dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
-        /* FIXME: how to react if put_user fails ? */
+        /* FIXME: how to react if mathemu_put_user fails ? */
         mem = (__u32 *) (&current->tss.fp_regs.fprs[(opc>>20)&15].f);
-        put_user(mem[0], dxb);
+        mathemu_put_user(mem[0], dxb);
+	return 0;
 }
 
 /*
  * Emulate LFPC D(B)
  */
 int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
-        /* FIXME: how to do that ?!? */
+	__u32 *dxb,temp;
+	__u32 opc = *((__u32 *) opcode);
+	dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+	mathemu_get_user(temp, dxb);
+	if(temp!=0)
+		display_emulation_not_implemented("lfpc");
         return 0;
 }
 
@@ -878,7 +1013,10 @@
  * Emulate STFPC D(B)
  */
 int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
-        /* FIXME: how to do that ?!? */
+	__u32 *dxb;
+	__u32 opc = *((__u32 *) opcode);
+	dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+	mathemu_put_user(current->tss.fp_regs.fpc, dxb);
         return 0;
 }
 
@@ -887,6 +1025,7 @@
  */
 int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
         /* FIXME: how to do that ?!? */
+	display_emulation_not_implemented("srnm");
         return 0;
 }
 
diff -urN linux-2.2.18-pre20/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- linux-2.2.18-pre20/arch/s390/kernel/process.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/process.c	Mon Dec  3 22:14:16 2001
@@ -76,7 +76,9 @@
                 if (bh_mask & bh_active) {
 #endif
                         do_bottom_half();
-                        continue;
+			__sti();
+	                if (!current->need_resched)
+	                        continue;
                 }
                 if (current->need_resched) {
                         schedule();
@@ -109,11 +111,13 @@
   0 returned you know you've got all the lines
  */
 
-int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_struct *tss,struct pt_regs * regs)
-{	
+static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+{
 	int linelen=0;
 	int regno,chaincnt;
 	u32 backchain,prev_backchain,endchain;
+	u32 ksp = 0;
+	char *mode = "???";
 
 	enum
 	{
@@ -134,34 +138,36 @@
 		sp_kern_backchain1
 	};
 
-	if(task)
-		tss=&task->tss;
-	if(tss)
-		regs=tss->regs;
+	if (task)
+		ksp = task->tss.ksp;
+	if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
+		ksp = regs->gprs[15];
+
+	if (regs)
+		mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
+		       "User" : "Kernel";
+
 	switch(line)
 	{
-	case sp_linefeed: linelen=sprintf(buff,"\n");
+	case sp_linefeed: 
+		linelen=sprintf(buff,"\n");
 		break;
 	case sp_psw:
 		if(regs)
-			linelen=sprintf(buff,"User PSW:    %08lx %08lx\n",
+			linelen=sprintf(buff, "%s PSW:    %08lx %08lx\n", mode,
 				(unsigned long) regs->psw.mask,
 				(unsigned long) regs->psw.addr);
 		else
 			linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
 		break;
 	case sp_ksp:
-		if(task)
-			linelen+=sprintf(&buff[linelen],"task: %08x ",(addr_t)task);
-		if(tss)
-			linelen+=sprintf(&buff[linelen],"tss: %08x ksp: %08x ",
-					 (addr_t)tss,(addr_t)tss->ksp);
-		if(regs)
-			linelen+=sprintf(&buff[linelen],"pt_regs: %08x\n",(addr_t)regs);
+		linelen=sprintf(&buff[linelen],
+				"task: %08x ksp: %08x pt_regs: %08x\n",
+				(addr_t)task, (addr_t)ksp, (addr_t)regs);
 		break;
 	case sp_gprs:
 		if(regs)
-			linelen=sprintf(buff,"User GPRS:\n");
+			linelen=sprintf(buff, "%s GPRS:\n", mode);
 		break;
 	case sp_gprs1 ... sp_gprs4:
 		if(regs)
@@ -176,7 +182,7 @@
 		break;
 	case sp_acrs:
 		if(regs)
-			linelen=sprintf(buff,"User ACRS:\n");
+			linelen=sprintf(buff, "%s ACRS:\n", mode);
 		break;	
         case sp_acrs1 ... sp_acrs4:
 		if(regs)
@@ -190,14 +196,14 @@
 		}
 		break;
 	case sp_kern_backchain:
-		if(tss&&tss->ksp&&regs)
-			linelen=sprintf(buff,"Kernel BackChain  CallChain    BackChain  CallChain\n");
+		if (ksp)
+			linelen=sprintf(buff, "Kernel BackChain  CallChain\n");
 		break;
 	default:
-		if(tss&&tss->ksp&&regs)
+		if (ksp)
 		{
 			
-			backchain=(tss->ksp&PSW_ADDR_MASK);
+			backchain=ksp&PSW_ADDR_MASK;
 			endchain=((backchain&(-8192))+8192);
 			prev_backchain=backchain-1;
 			line-=sp_kern_backchain1;
@@ -206,34 +212,48 @@
 				if((backchain==0)||(backchain>=endchain)
 				   ||(chaincnt>=8)||(prev_backchain>=backchain))
 					break;
-				if((chaincnt>>1)==line)
+				if(chaincnt==line)
 				{
-					linelen+=sprintf(&buff[linelen],"%s%08x   %08x     ",
-							 (chaincnt&1) ? "":"       ",
-							 backchain,*(u32 *)(backchain+56));
-				}
-				if((chaincnt>>1)>line)
+					linelen+=sprintf(&buff[linelen],"       %08x   [<%08x>]\n",
+							 backchain,
+							 *(u32 *)(backchain+56)&PSW_ADDR_MASK);
 					break;
+				}
 				prev_backchain=backchain;
 				backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
 			}
-			if(linelen)
-				linelen+=sprintf(&buff[linelen],"\n");
 		}
 	}
 	return(linelen);
 }
 
 
-void show_regs(struct task_struct * task,struct thread_struct *tss,struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
 {
 	char buff[80];
 	int line;
+
+        printk("CPU:    %d\n",smp_processor_id());
+        printk("Process %s (pid: %d, stackpage=%08X)\n",
+                current->comm, current->pid, 4096+(addr_t)current);
 	
-	for(line=0;sprintf_regs(line,buff,task,tss,regs);line++)
+	for (line = 0; sprintf_regs(line, buff, current, regs); line++)
 		printk(buff);
 }
 
+char *task_show_regs(struct task_struct *task, char *buffer)
+{
+	int line, len;
+
+	for (line = 0; ; line++)
+	{
+		len = sprintf_regs(line, buffer, task, task->tss.regs);
+		if (!len) break;
+		buffer += len;
+	}
+	return buffer;
+}
+
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
         int clone_arg = flags | CLONE_VM;
@@ -283,15 +303,15 @@
         struct task_struct * p, struct pt_regs * regs)
 {
         struct stack_frame
-          {
-            unsigned long back_chain;
-            unsigned long eos;
-            unsigned long glue1;
-            unsigned long glue2;
-            unsigned long scratch[2];
-            unsigned long gprs[10];    /* gprs 6 -15                       */
-            unsigned long fprs[4];     /* fpr 4 and 6                      */
-            unsigned long empty[4];
+	{
+		unsigned long back_chain;
+		unsigned long eos;
+		unsigned long glue1;
+		unsigned long glue2;
+		unsigned long scratch[2];
+		unsigned long gprs[10];    /* gprs 6 -15                       */
+		unsigned long fprs[4];     /* fpr 4 and 6                      */
+		unsigned long empty[4];
 #if CONFIG_REMOTE_DEBUG
 		gdb_pt_regs childregs;
 #else
@@ -344,7 +364,7 @@
 
         lock_kernel();
         clone_flags = regs.gprs[3];
-        newsp = regs.gprs[2];
+        newsp = regs.orig_gpr2;
         if (!newsp)
                 newsp = regs.gprs[15];
         ret = do_fork(clone_flags, newsp, &regs);
@@ -383,7 +403,19 @@
                 goto out;
         error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
 	if (error == 0)
+	{
 		current->flags &= ~PF_DTRACE;
+		current->tss.fp_regs.fpc=0;
+		if(MACHINE_HAS_IEEE)
+		{
+			__asm__ __volatile__
+			("sr  0,0\n\t"
+			 "sfpc 0,0\n\t"
+				:
+			        :
+                                :"0");
+		}
+	}
         putname(filename);
 out:
         unlock_kernel();
diff -urN linux-2.2.18-pre20/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c
--- linux-2.2.18-pre20/arch/s390/kernel/ptrace.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/ptrace.c	Mon Dec  3 22:14:16 2001
@@ -229,7 +229,7 @@
 	struct vm_area_struct * vma;
 	addr=ADDR_BITS_REMOVE(addr);
 	vma= find_extend_vma(tsk, addr);
-
+     
 	if (!vma)
 		return -EIO;
 	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
@@ -478,15 +478,15 @@
 	/* ieee_instruction_pointer from the user structure DJB */
 	if(child!=current)
 	{
-	if (!(child->flags & PF_PTRACED))
-		goto out;
-	if (child->state != TASK_STOPPED) 
-	{
-		if (request != PTRACE_KILL)
+		if (!(child->flags & PF_PTRACED))
+			goto out;
+		if (child->state != TASK_STOPPED) 
+		{
+			if (request != PTRACE_KILL)
+				goto out;
+		}
+		if (child->p_pptr != current)
 			goto out;
-	}
-	if (child->p_pptr != current)
-		goto out;
 	}
 	switch (request) 
 	{
diff -urN linux-2.2.18-pre20/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c
--- linux-2.2.18-pre20/arch/s390/kernel/s390_ext.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/s390_ext.c	Mon Dec  3 22:14:16 2001
@@ -13,7 +13,7 @@
 #include <asm/s390_ext.h>
 
 /*
- * Simple hash strategy: index = ((code >> 8) + code) & 0xff;
+ * Simple hash strategy: index = code & 0xff;
  * ext_int_hash[index] is the start of the list for all external interrupts
  * that hash to this index. With the current set of external interrupts 
  * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
@@ -27,7 +27,7 @@
         ext_int_info_t *p;
         int index;
 
-        index = (code + (code >> 8)) & 0xff;
+        index = code & 0xff;
         p = ext_int_hash[index];
         while (p != NULL) {
                 if (p->code == code)
@@ -54,7 +54,7 @@
         ext_int_info_t *p, *q;
         int index;
 
-        index = (code + (code >> 8)) & 0xff;
+        index = code & 0xff;
         q = NULL;
         p = ext_int_hash[index];
         while (p != NULL) {
diff -urN linux-2.2.18-pre20/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- linux-2.2.18-pre20/arch/s390/kernel/s390_ksyms.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/s390_ksyms.c	Mon Dec  3 22:14:16 2001
@@ -5,20 +5,18 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/interrupt.h>
 #include <asm/debug.h>
 #include <linux/genhd.h>
 #include <asm/ccwcache.h>
 #include <asm/irq.h>
 #include <asm/string.h>
-#include <asm/checksum.h>
+#include <asm/checksum.h>
 #include <asm/s390_ext.h>
 #include <asm/s390dyn.h>
 #include <asm/ebcdic.h>
 #include <asm/timex.h>
 #include <asm/delay.h>
-#if CONFIG_CHANDEV
-#include <asm/chandev.h>
-#endif
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
@@ -27,6 +25,7 @@
  * I/O subsystem
  */
 EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
 EXPORT_SYMBOL(do_IO);
 EXPORT_SYMBOL(resume_IO);
 EXPORT_SYMBOL(ioinfo);
@@ -42,21 +41,31 @@
 EXPORT_SYMBOL(s390_device_register);
 EXPORT_SYMBOL(s390_device_unregister);
 
+EXPORT_SYMBOL(s390_bh_lock);
+
 EXPORT_SYMBOL(ccw_alloc_request);
 EXPORT_SYMBOL(ccw_free_request);
 
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
-/*
+/* 
  * debug feature
  */
 EXPORT_SYMBOL(debug_register);
 EXPORT_SYMBOL(debug_unregister); 
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
 EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_int_event);
 EXPORT_SYMBOL(debug_text_event);
 EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_int_exception);
 EXPORT_SYMBOL(debug_text_exception);
+EXPORT_SYMBOL(debug_hex_view);
+EXPORT_SYMBOL(debug_ascii_view);
+EXPORT_SYMBOL(debug_ebcdic_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
 
 /*
  * memory management
@@ -81,6 +90,7 @@
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
+EXPORT_SYMBOL_NOVERS(strstr);
 
 EXPORT_SYMBOL_NOVERS(_ascebc_500);
 EXPORT_SYMBOL_NOVERS(_ebcasc_500);
@@ -92,6 +102,8 @@
 /*
  * misc.
  */
+EXPORT_SYMBOL(__copy_from_user_fixup);
+EXPORT_SYMBOL(__copy_to_user_fixup);
 EXPORT_SYMBOL(__udelay);
 #ifdef CONFIG_SMP
 #include <asm/smplock.h>
@@ -104,12 +116,13 @@
 EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
+EXPORT_SYMBOL(smp_do_callback_all);
 #endif
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(genhd_dasd_name);
 
-#if CONFIG_IP_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
 /* Required for lcs gigibit ethernet multicast support */
 EXPORT_SYMBOL(arp_mc_map);
 #endif
diff -urN linux-2.2.18-pre20/arch/s390/kernel/s390dyn.c linux/arch/s390/kernel/s390dyn.c
--- linux-2.2.18-pre20/arch/s390/kernel/s390dyn.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/s390dyn.c	Mon Dec  3 22:14:16 2001
@@ -3,7 +3,7 @@
  *   S/390 dynamic device attachment
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
diff -urN linux-2.2.18-pre20/arch/s390/kernel/s390fpu.c linux/arch/s390/kernel/s390fpu.c
--- linux-2.2.18-pre20/arch/s390/kernel/s390fpu.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/s390/kernel/s390fpu.c	Mon Dec  3 22:14:16 2001
@@ -80,6 +80,11 @@
 {
 	int has_ieee=MACHINE_HAS_IEEE;
 
+	/* If we don't mask with the FPC_VALID_MASK here
+	 * we've got a very quick shutdown -h now command
+         * via a kernel specification exception.
+	 */
+	fpregs->fpc&=FPC_VALID_MASK;
 	asm volatile ("LD   0,8(%0)\n\t"
 		      "LD   2,24(%0)\n\t"
 		      "LD   4,40(%0)\n\t"
diff -urN linux-2.2.18-pre20/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c
--- linux-2.2.18-pre20/arch/s390/kernel/s390io.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/s390io.c	Mon Dec  3 22:14:16 2001
@@ -33,16 +33,16 @@
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
 
-#undef CONFIG_DEBUG_IO    
+#undef  CONFIG_DEBUG_IO
 #define CONFIG_DEBUG_CRW
 
 #define REIPL_DEVID_MAGIC 0x87654321
 
 struct s390_irqaction  init_IRQ_action;
-unsigned int      highest_subchannel;
-ioinfo_t         *ioinfo_head = NULL;
-ioinfo_t         *ioinfo_tail = NULL;
-ioinfo_t         *ioinfo[__MAX_SUBCHANNELS] = {
+unsigned int           highest_subchannel;
+ioinfo_t              *ioinfo_head = NULL;
+ioinfo_t              *ioinfo_tail = NULL;
+ioinfo_t              *ioinfo[__MAX_SUBCHANNELS] = {
 	[0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
 };
 
@@ -83,9 +83,9 @@
 
 int  s390_DevicePathVerification( int irq, __u8 domask );
 
-extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int enable_none(unsigned int irq);
-extern int disable_none(unsigned int irq);
+extern int  do_none(unsigned int irq, int cpu, struct pt_regs * regs);
+extern int  enable_none(unsigned int irq);
+extern int  disable_none(unsigned int irq);
 extern void tod_wait(unsigned long usecs);
 
 asmlinkage void do_IRQ( struct pt_regs regs,
@@ -124,9 +124,9 @@
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
-                      unsigned long  irqflags,
-                      const char    *devname,
-                      void          *dev_id)
+                              unsigned long            irqflags,
+                              const char              *devname,
+                              void                    *dev_id)
 {
 	int               retval;
 	struct s390_irqaction *action;
@@ -137,35 +137,35 @@
 	if ( !io_handler || !dev_id )
 		return -EINVAL;
 
-   /*
-    * during init_IRQ() processing we don't have memory
-    *  management yet, thus need to use a statically
-    *  allocated irqaction control block
-    */
-   if ( init_IRQ_complete )
-   {
+	/*
+	 * during init_IRQ() processing we don't have memory
+	 *  management yet, thus need to use a statically
+	 *  allocated irqaction control block
+	 */
+	if ( init_IRQ_complete )
+	{
 		action = (struct s390_irqaction *)
 		            kmalloc( sizeof(struct s390_irqaction),
 		                     GFP_KERNEL);
-   }
-   else
-   {
-      action = &init_IRQ_action;
+	}
+	else
+	{
+		action = &init_IRQ_action;
 
-   } /* endif */
+	} /* endif */
 
 	if (!action)
-   {
+	{
 		return -ENOMEM;
 
-   } /* endif */
+	} /* endif */
 
 	action->handler = io_handler;
 	action->flags   = irqflags;
 	action->name    = devname;
 	action->dev_id  = dev_id;
 
-	retval = s390_setup_irq(irq, action);
+	retval = s390_setup_irq( irq, action);
 
 	if ( init_IRQ_complete )
 	{
@@ -174,10 +174,10 @@
 			s390_DevicePathVerification( irq, 0 );
 		}
 		else
-	{
-		kfree(action);
+		{
+			kfree(action);
 
-	} /* endif */
+		} /* endif */
 
 	} /* endif */
 
@@ -228,7 +228,7 @@
 
 	} /* endif */
 
-	s390irq_spin_lock_irqsave(irq,flags);
+	s390irq_spin_lock_irqsave( irq, flags);
 
 #ifdef  CONFIG_KERNEL_DEBUG
 	if ( irq != cons_dev )
@@ -251,7 +251,7 @@
 			ioinfo[irq]->ui.flags.unready = 1;
 
 			do
-         {
+			{
 				ret = disable_subchannel( irq);
 
 				count++;
@@ -305,15 +305,15 @@
 						disable_subchannel( irq);
 
 						if ( ioinfo[irq]->ui.flags.busy )
-				{
-					printk( KERN_CRIT"free_irq(%04X) "
-					       "- device %04X busy, retry "
-					       "count exceeded\n",
-					       irq,
-					       ioinfo[irq]->devstat.devno);
-
-				} /* endif */
+					   {
+							printk( KERN_CRIT"free_irq(%04X) "
+							       "- device %04X busy, retry "
+							       "count exceeded\n",
+						   	    irq,
+						      	 ioinfo[irq]->devstat.devno);
 
+                  } /* endif */
+						
 						break; /* sigh, let's give up ... */
 
 					} /* endif */
@@ -325,11 +325,11 @@
 			if ( init_IRQ_complete )
 				kfree( ioinfo[irq]->irq_desc.action );
 
-			ioinfo[irq]->irq_desc.action  = NULL;
-			ioinfo[irq]->ui.flags.ready   = 0;
+			ioinfo[irq]->irq_desc.action           = NULL;
+			ioinfo[irq]->ui.flags.ready            = 0;
 			ioinfo[irq]->irq_desc.handler->enable  = enable_none;
 			ioinfo[irq]->irq_desc.handler->disable = disable_none;
-			ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
+			ioinfo[irq]->ui.flags.unready          = 0; /* deregister ended */
 
 			ioinfo[irq]->nopfunc = NULL;
 
@@ -405,15 +405,15 @@
  */
 static int enable_subchannel( unsigned int irq)
 {
-	int            ret;
-   int            ccode;
-   int            retry = 5;
+	int   ret;
+	int   ccode;
+	int   retry = 5;
 
-   if ( irq > highest_subchannel || irq < 0 )
-   {
-      return( -ENODEV );
+	if ( irq > highest_subchannel || irq < 0 )
+	{
+		return( -ENODEV );
 
-   } /* endif */
+	} /* endif */
 
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 		return( -ENODEV);
@@ -425,18 +425,18 @@
 	if (  ioinfo[irq]->ui.flags.d_disable )
 	{
 		ioinfo[irq]->ui.flags.d_disable = 0;
-		ret                            = 0;
+		ret                             = 0;
 	}
 	else
 	{
 		ccode = stsch(irq, &(ioinfo[irq]->schib) );
 
-      if ( ccode )
-      {
-          ret = -ENODEV;
-      }
-      else
-      {
+		if ( ccode )
+		{
+			ret = -ENODEV;
+		}
+		else
+		{
 			ioinfo[irq]->schib.pmcw.ena = 1;
 
 			if ( irq == cons_dev )
@@ -445,28 +445,28 @@
 			}
 			else	
 			{
-			ioinfo[irq]->schib.pmcw.isc = 3;
+				ioinfo[irq]->schib.pmcw.isc = 3;
 
 			} /* endif */
 
-         do
-         {
+			do
+			{
 				ccode = msch( irq, &(ioinfo[irq]->schib) );
 
-   		   switch (ccode) {
-            case 0:
-               ret = 0;
-               break;
+				switch (ccode) {
+				case 0:
+					ret = 0;
+					break;
 
-            case 1:
-	   			/*
+				case 1:
+					/*
 					 * very bad, requires interrupt alike
 					 *  processing, where "rbh" is a dummy
 					 *  parameter for interface compatibility
 					 *  only. Bottom-half handling cannot be
 					 *  required as this must be an
 					 *  unsolicited interrupt (!busy).
-	   			 */
+					 */
 
 					ioinfo[irq]->ui.flags.s_pend = 1;
 					s390_process_IRQ( irq );
@@ -475,8 +475,8 @@
 					ret = -EIO;    /* might be overwritten */
 					               /* ... on re-driving    */
 					               /* ... the msch() */
-               retry--;
-               break;
+					retry--;
+					break;
 
 				case 2:
 					tod_wait(100);	/* allow for recovery */
@@ -484,24 +484,24 @@
 					retry--;
 					break;
 
-            case 3:
+				case 3:
 					ioinfo[irq]->ui.flags.oper = 0;
-               ret = -ENODEV;
-               break;
+					ret = -ENODEV;
+					break;
 
-            default:
+				default:
 					printk( KERN_CRIT"enable_subchannel(%04X) "
 					        " : ccode 2 on msch() for device "
 					        "%04X received !\n",
 					        irq,
 					        ioinfo[irq]->devstat.devno);
 
-               ret = -ENODEV; // never reached
-            }
+					ret = -ENODEV; // never reached
+				}
 
-         } while ( (ccode == 1) && retry );
+			} while ( (ccode == 1) && retry );
 
-      } /* endif */
+		} /* endif */
 
 	}  /* endif */
 
@@ -514,9 +514,9 @@
  */
 static int disable_subchannel( unsigned int irq)
 {
-	int            cc;          /* condition code */
-	int            ret;         /* function return value */
-   int            retry = 5;
+	int  cc;          /* condition code */
+	int  ret;         /* function return value */
+	int  retry = 5;
 
 	if ( irq > highest_subchannel )
 	{
@@ -525,7 +525,7 @@
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		return( -ENODEV);
-   }
+	}
 	else if ( ioinfo[irq]->ui.flags.busy )
 	{
 		/*
@@ -554,17 +554,17 @@
 		{
 			ioinfo[irq]->schib.pmcw.ena = 0;
 
-         do
-         {
+			do
+			{
 				cc = msch( irq, &(ioinfo[irq]->schib) );
 
-	   		switch (cc) {
-		   	case 0 :
-			   	ret = 0;   /* done */
-				   break;
+				switch (cc) {
+				case 0 :
+					ret = 0;   /* done */
+					break;
 
-   			case 1 :
-	   			/*
+				case 1 :
+					/*
 					 * very bad, requires interrupt alike
   					 *  processing, where "rbh" is a dummy
 					 *  parm for interface compatibility
@@ -577,46 +577,46 @@
 					ioinfo[irq]->ui.flags.s_pend = 0;
 
 					ret = -EIO; /* might be overwritten  */
-					               /* ... on re-driving the */
-					               /* ... msch() call       */
-               retry--;
-				   break;
-
-   			case 2 :
-	   			/*
-		   		 * *** must not occur !                                    ***
-			   	 * ***                                                     ***
+					            /* ... on re-driving the */
+					            /* ... msch() call       */
+					retry--;
+					break;
+
+				case 2 :
+					/*
+					 * *** must not occur !              ***
+					 * ***                               ***
 					 * *** indicates our internal        ***
 					 * *** interrupt accounting is out   ***
-   				 * ***  of sync ===> panic()                               ***
-	   			 */
+					 * ***  of sync ===> panic()         ***
+					 */
 					printk( KERN_CRIT"disable_subchannel(%04X) "
 					        "- unexpected busy condition for "
 							  "device %04X received !\n",
 					        irq,
 					        ioinfo[irq]->devstat.devno);
 					ret = -EBUSY;
-				   break;
+					break;
 
-   			case 3 :
-	   			/*
+				case 3 :
+					/*
 					 * should hardly occur ?!
-			   	 */
+					 */
 					ioinfo[irq]->ui.flags.oper      = 0;
 					ioinfo[irq]->ui.flags.d_disable = 1;
 
 					ret = 0; /* if the device has gone we */
 					         /* ... don't need to disable */
 					         /* ... it anymore !    */
-			   	break;
+					break;
 
-   			default :
-	   			ret = -ENODEV;  // never reached ...
-		   		break;
+				default :
+					ret = -ENODEV;  // never reached ...
+					break;
 
-			   } /* endswitch */
+				} /* endswitch */
 
-         } while ( (cc == 1) && retry );
+			} while ( (cc == 1) && retry );
 
 		} /* endif */
 
@@ -716,10 +716,10 @@
 	 * As we don't know about the calling environment
 	 *  we assure running disabled. Before leaving the
 	 *  function we resestablish the old environment.
-    *
-    * Note : as we don't need a system wide lock, therefore
-    *        we shouldn't use cli(), but __cli() as this
-    *        affects the current CPU only.
+	 *
+	 * Note : as we don't need a system wide lock, therefore
+	 *        we shouldn't use cli(), but __cli() as this
+	 *        affects the current CPU only.
 	 */
 	__save_flags(flags);
 	__cli();
@@ -730,7 +730,7 @@
 	cr6 = 0;
 	asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
 
-   s390_process_subchannels();
+	s390_process_subchannels();
 
 	/*
 	 * enable default I/O-interrupt sublass 3
@@ -740,7 +740,7 @@
 
 	s390_device_recognition_all();
 
-   init_IRQ_complete = 1;
+	init_IRQ_complete = 1;
 
 	__restore_flags(flags);
 
@@ -788,7 +788,7 @@
 	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
 	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
 	ioinfo[irq]->orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )
-	                          && (flag & DOIO_SUPPRESS_INTER) );
+	                           && (flag & DOIO_SUPPRESS_INTER) );
 
 	if ( flag & DOIO_VALID_LPM )
 	{
@@ -800,7 +800,7 @@
 
 	} /* endif */
 
-	ioinfo[irq]->orb.cpa = (ccw1_t *)virt_to_phys( cpa);
+	ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
 
 	/*
 	 * If sync processing was requested we lock the sync ISC, modify the
@@ -849,7 +849,7 @@
 	case 0:
 
 		if ( !ioinfo[irq]->ui.flags.w4sense )
-      {
+		{
 			/*
 			 * init the device driver specific devstat irb area
 			 *
@@ -895,7 +895,7 @@
 		} /* endif */
 
 		ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
-
+		
 		/*
 		 * If synchronous I/O processing is requested, we have
 		 *  to wait for the corresponding interrupt to occur by
@@ -906,54 +906,54 @@
 		 */
 		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
 		{
-			int              io_sub = -1;
-         psw_t            io_new_psw;
-         int              ccode;
+			psw_t            io_new_psw;
+			int              ccode;
 			uint64_t         time_start;    	
 			uint64_t         time_curr;    	
 
-			int              ready = 0;
-         struct _lowcore *lc    = NULL;
+			int              ready    = 0;
+			int              io_sub   = -1;
+			struct _lowcore *lc       = NULL;
 			int              do_retry = 1;
 
-         /*
+			/*
 			 * We shouldn't perform a TPI loop, waiting for an
 			 *  interrupt to occur, but should load a WAIT PSW
 			 *  instead. Otherwise we may keep the channel subsystem
 			 *  busy, not able to present the interrupt. When our
 			 *  sync. interrupt arrived we reset the I/O old PSW to
 			 *  its original value.
-          */
-         memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
+			 */
+			memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
 
 			ccode = iac();
 
 			switch (ccode) {
-				case 0:  		// primary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_PRIM_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_SEC_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_ACC_REG_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_HOME_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "start_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
+			case 0:  		// primary-space
+				io_sync_wait.mask =   _IO_PSW_MASK
+				                    | _PSW_PRIM_SPACE_MODE
+				                    | _PSW_IO_WAIT;
+				break;
+			case 1:			// secondary-space
+				io_sync_wait.mask =   _IO_PSW_MASK
+				                    | _PSW_SEC_SPACE_MODE
+				                    | _PSW_IO_WAIT;
+				break;
+			case 2:			// access-register
+				io_sync_wait.mask =   _IO_PSW_MASK
+				                    | _PSW_ACC_REG_MODE
+				                    | _PSW_IO_WAIT;
+				break;
+			case 3:			// home-space	
+				io_sync_wait.mask =   _IO_PSW_MASK
+				                    | _PSW_HOME_SPACE_MODE
+				                    | _PSW_IO_WAIT;
+				break;
+			default:
+				panic( "start_IO() : unexpected "
+				       "address-space-control %d\n",
+				       ccode);
+				break;
 			} /* endswitch */
 
 			io_sync_wait.addr = FIX_PSW(&&io_wakeup);
@@ -974,8 +974,8 @@
 				{
 					tpi_info_t tpi_info;
 
-			do
-			{
+					do
+					{
 						if ( tpi(&tpi_info) == 1 )
 						{
 							io_sub = tpi_info.irq;
@@ -990,20 +990,20 @@
 								do_retry = 0;          							
 
 						} /* endif */
-
+				
 					} while ( do_retry );
 				}
 				else
 				{
-      		asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
+					asm volatile ("lpsw %0" : : "m" (io_sync_wait));
 
 io_wakeup:
-				io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+					io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
 
 				} /* endif */
 
  				if ( do_retry )
-				ready = s390_process_IRQ( io_sub );
+					ready = s390_process_IRQ( io_sub );
 
 				/*
 				 * surrender when retry count's exceeded ...
@@ -1032,9 +1032,9 @@
 		memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
 		        '\0', sizeof( irb_t) );
 
-      /*
-       * Let the common interrupt handler process the pending status.
-       *  However, we must avoid calling the user action handler, as
+		/*
+		 * Let the common interrupt handler process the pending status.
+		 *  However, we must avoid calling the user action handler, as
 		 *  it won't be prepared to handle a pending status during
 		 *  do_IO() processing inline. This also implies that process_IRQ
 		 *  must terminate synchronously - especially if device sensing
@@ -1076,8 +1076,8 @@
 	
 			if ( ioinfo[irq]->opm == 0 ) 	
 			{
-			ret                        = -ENODEV;
-			ioinfo[irq]->ui.flags.oper  = 0;
+				ret                         = -ENODEV;
+				ioinfo[irq]->ui.flags.oper  = 0;
          }
 			else
 			{
@@ -1088,12 +1088,12 @@
 			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
 
 #ifdef CONFIG_DEBUG_IO
-      	{
-	      char buffer[80];
+			{
+			char buffer[80];
 
 			stsch(irq, &(ioinfo[irq]->schib) );
 
-   	   sprintf( buffer, "s390_start_IO(%04X) - irb for "
+			sprintf( buffer, "s390_start_IO(%04X) - irb for "
 			         "device %04X, after status pending\n",
 			         irq,
 			         ioinfo[irq]->devstat.devno );
@@ -1102,7 +1102,7 @@
 			                 &(ioinfo[irq]->devstat.ii.irb) ,
 			                 sizeof(irb_t));
 
-   	   sprintf( buffer, "s390_start_IO(%04X) - schib for "
+			sprintf( buffer, "s390_start_IO(%04X) - schib for "
 			         "device %04X, after status pending\n",
 			         irq,
 			         ioinfo[irq]->devstat.devno );
@@ -1113,7 +1113,7 @@
 
 
 			if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
-         {
+			{
 				sprintf( buffer, "s390_start_IO(%04X) - sense "
 				         "data for "
 				         "device %04X, after status pending\n",
@@ -1125,12 +1125,12 @@
 		((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);
 
 			} /* endif */
-      	}
+			}
 #endif
 		}
 		else
 		{
-			ret                        = -EIO;
+			ret                         = -EIO;
 			ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
 			ioinfo[irq]->ui.flags.oper  = 1;
 
@@ -1144,7 +1144,7 @@
 		break;
 
 	default:            /* device/path not operational */
-
+		
 		if ( flag & DOIO_VALID_LPM )
 		{
 			ioinfo[irq]->opm &= ~lpm;
@@ -1154,27 +1154,27 @@
 			ioinfo[irq]->opm = 0;
 
 		} /* endif */
-
+	
 		if ( ioinfo[irq]->opm == 0 ) 	
 		{
 			ioinfo[irq]->ui.flags.oper  = 0;
-		ioinfo[irq]->devstat.flag    |= DEVSTAT_NOT_OPER;
+			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
 
 		} /* endif */
 
 		ret = -ENODEV;
 
 		memcpy( ioinfo[irq]->irq_desc.action->dev_id,
-			&(ioinfo[irq]->devstat),
-			sizeof( devstat_t) );
+		        &(ioinfo[irq]->devstat),
+		        sizeof( devstat_t) );
 
 #ifdef CONFIG_DEBUG_IO
-      	{
-	      char buffer[80];
+		{
+			char buffer[80];
 
    			stsch(irq, &(ioinfo[irq]->schib) );
 
-   	   sprintf( buffer, "s390_start_IO(%04X) - schib for "
+			sprintf( buffer, "s390_start_IO(%04X) - schib for "
 			         "device %04X, after 'not oper' status\n",
 			         irq,
 			         ioinfo[irq]->devstat.devno );
@@ -1211,7 +1211,7 @@
 
 		} while ( retry && (iret == -EBUSY ) );
 
-		sync_isc_locked             = 0;    // local setting
+		sync_isc_locked              = 0;    // local setting
 		ioinfo[irq]->ui.flags.syncio = 0;    // global setting
 
 		spin_unlock_irqrestore( &sync_isc, psw_flags);
@@ -1222,7 +1222,7 @@
 	{
 		ioinfo[irq]->ui.flags.repnone = 0;
 
-	} /* endif */
+   } /* endif */
 
 	return( ret);
 }
@@ -1324,27 +1324,27 @@
 		ccode = rsch( irq);
 
 		switch (ccode) {
-			case 0 :
-				break;
+		case 0 :
+			break;
 
-			case 1 :
+		case 1 :
 		  	s390_process_IRQ( irq );
-				ret = -EBUSY;
-				break;
+			ret = -EBUSY;
+			break;
 
-			case 2 :
-				ret = -EINVAL;
-				break;
+		case 2 :
+			ret = -EINVAL;
+			break;
 
-			case 3 :
-				/*
-				 * useless to wait for request completion
-				 *  as device is no longer operational !
-				 */
+		case 3 :
+			/*
+			 * useless to wait for request completion
+			 *  as device is no longer operational !
+			 */
 			ioinfo[irq]->ui.flags.oper = 0;
 			ioinfo[irq]->ui.flags.busy = 0;
-				ret                       = -ENODEV;
-				break;
+			ret                        = -ENODEV;
+			break;
 
 		} /* endswitch */          	
 		
@@ -1364,7 +1364,7 @@
  *       it allows the device interrupt handler to associate the upcoming
  *       interrupt with the halt_IO() request.
  */
-int halt_IO( int          irq,
+int halt_IO( int           irq,
              unsigned long user_intparm,
              unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
 {
@@ -1482,13 +1482,13 @@
 			{
 				int              io_sub;
 				__u32            io_parm;
-  		      psw_t            io_new_psw;
-            int              ccode;
+				psw_t            io_new_psw;
+				int              ccode;
   	
 				int              ready = 0;
-	         struct _lowcore *lc    = NULL;
+				struct _lowcore *lc    = NULL;
 
-	         /*
+				/*
 				 * We shouldn't perform a TPI loop, waiting for
 				 *  an interrupt to occur, but should load a
 				 *  WAIT PSW instead. Otherwise we may keep the
@@ -1504,31 +1504,31 @@
 				ccode = iac();
 
 				switch (ccode) {
-					case 0:  		// primary-space
-						io_sync_wait.mask =   _IO_PSW_MASK
-						                    | _PSW_PRIM_SPACE_MODE
-						                    | _PSW_IO_WAIT;
-						break;
-					case 1:			// secondary-space
-						io_sync_wait.mask =   _IO_PSW_MASK
-						                    | _PSW_SEC_SPACE_MODE
-						                    | _PSW_IO_WAIT;
-						break;
-					case 2:			// access-register
-						io_sync_wait.mask =   _IO_PSW_MASK
-						                    | _PSW_ACC_REG_MODE
-						                    | _PSW_IO_WAIT;
-						break;
-					case 3:			// home-space	
-						io_sync_wait.mask =   _IO_PSW_MASK
-						                    | _PSW_HOME_SPACE_MODE
-						                    | _PSW_IO_WAIT;
-						break;
-					default:
-						panic( "halt_IO() : unexpected "
-						       "address-space-control %d\n",
-						       ccode);
-						break;
+				case 0:  		// primary-space
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_PRIM_SPACE_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				case 1:			// secondary-space
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_SEC_SPACE_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				case 2:			// access-register
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_ACC_REG_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				case 3:			// home-space	
+					io_sync_wait.mask =   _IO_PSW_MASK
+					                    | _PSW_HOME_SPACE_MODE
+					                    | _PSW_IO_WAIT;
+					break;
+				default:
+					panic( "halt_IO() : unexpected "
+					       "address-space-control %d\n",
+					       ccode);
+					break;
 				} /* endswitch */
 
 				io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
@@ -1568,7 +1568,7 @@
 			memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
 			        '\0', sizeof( irb_t) );
 
-	      /*
+			/*
 			 * Let the common interrupt handler process the pending
 			 *  status. However, we must avoid calling the user
 			 *  action handler, as it won't be prepared to handle
@@ -1600,13 +1600,13 @@
 			 */
 			if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
 			{
-				ret                        = -ENODEV;
+				ret                         = -ENODEV;
 				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
 				ioinfo[irq]->ui.flags.oper  = 0;
 			}
 			else
 			{
-				ret                        = -EIO;
+				ret                         = -EIO;
 				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
 				ioinfo[irq]->ui.flags.oper  = 1;
 
@@ -1630,8 +1630,8 @@
 		{
 			disable_cpu_sync_isc( irq );
   	
-			sync_isc_locked             = 0;    // local setting
-		   ioinfo[irq]->ui.flags.syncio = 0;    // global setting
+			sync_isc_locked              = 0;    // local setting
+			ioinfo[irq]->ui.flags.syncio = 0;    // global setting
   	
 			spin_unlock_irqrestore( &sync_isc, psw_flags);
   	
@@ -1653,7 +1653,7 @@
               unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
 {
 	int            ret;
-	int			ccode;
+	int            ccode;
 	unsigned long  psw_flags;
 
 	int            sync_isc_locked = 0;
@@ -1666,7 +1666,7 @@
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		return( -ENODEV);
-	}
+   }
 
 	/*
 	 * we only allow for halt_IO if the device has an I/O handler associated
@@ -1675,62 +1675,62 @@
 	{
 		ret = -ENODEV;
 	}
-		/*
+	/*
 	 * we ignore the halt_io() request if ending_status was received but
 	 *  a SENSE operation is waiting for completion.
-		 */
+	 */
 	else if ( ioinfo[irq]->ui.flags.w4sense )
 	{
 		ret = 0;
 	}
-		/*
+	/*
 	 * We don't allow for halt_io with a sync do_IO() requests pending.
 	 *  Concurrent I/O is possible in SMP environments only, but the
 	 *  sync. I/O request can be gated to one CPU at a time only.
-		 */
+	 */
 	else if ( ioinfo[irq]->ui.flags.syncio )
-      {
+	{
 		ret = -EBUSY;
-}
+	}
 	else
 	{
-/*
+		/*
 		 * If sync processing was requested we lock the sync ISC,
 		 *  modify the device to present interrupts for this ISC only
 		 *  and switch the CPU to handle this ISC + the console ISC
 		 *  exclusively.
- */
+		 */
 		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-{
+		{
 			//
 			// check whether we run recursively (sense processing)
 			//
 			if ( !ioinfo[irq]->ui.flags.syncio )
 			{
 				spin_lock_irqsave( &sync_isc, psw_flags);
-
+  	
 				ret = enable_cpu_sync_isc( irq);
 
 				if ( ret )
-	{
+				{
 					spin_unlock_irqrestore( &sync_isc,
 					                        psw_flags);
 					return( ret);
 				}
 				else
-		{
+				{
 					sync_isc_locked              = 1; // local
 					ioinfo[irq]->ui.flags.syncio = 1; // global
 
 				} /* endif */  	
+  	
+			} /* endif */
 
 		} /* endif */
 
-	} /* endif */
-
-	/*
+		/*
 		 * Issue "Halt subchannel" and process condition code
-	 */
+		 */
 		ccode = csch( irq );
 
 		switch ( ccode ) {
@@ -1739,7 +1739,7 @@
 			ioinfo[irq]->ui.flags.haltio = 1;
 
 			if ( !ioinfo[irq]->ui.flags.doio )
-	{
+			{
 				ioinfo[irq]->ui.flags.busy   = 1;
 				ioinfo[irq]->u_intparm       = user_intparm;
 				ioinfo[irq]->devstat.cstat   = 0;
@@ -1748,12 +1748,12 @@
 				ioinfo[irq]->devstat.flag    = DEVSTAT_CLEAR_FUNCTION;
 				ioinfo[irq]->devstat.scnt    = 0;
 
-	}
-	else
-	{
+			}
+			else
+			{
 				ioinfo[irq]->devstat.flag   |= DEVSTAT_CLEAR_FUNCTION;
 
-	} /* endif */
+			} /* endif */
 
 			/*
 			 * If synchronous I/O processing is requested, we have
@@ -1764,16 +1764,16 @@
 			 *  pops up.
 			 */
 			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-	{
+			{
 				int              io_sub;
 				__u32            io_parm;
 				psw_t            io_new_psw;
 				int              ccode;
-
+  	
 				int              ready = 0;
 				struct _lowcore *lc    = NULL;
 
-	/*
+				/*
 				 * We shouldn't perform a TPI loop, waiting for
 				 *  an interrupt to occur, but should load a
 				 *  WAIT PSW instead. Otherwise we may keep the
@@ -1781,7 +1781,7 @@
 				 *  the interrupt. When our sync. interrupt
 				 *  arrived we reset the I/O old PSW to its
 				 *  original value.
-	 */
+				 */
 				memcpy( &io_new_psw,
 				        &lc->io_new_psw,
 				        sizeof(psw_t));
@@ -1818,14 +1818,14 @@
 
 				io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
 
-	/*
+				/*
 				 * Martin didn't like modifying the new PSW, now we take
 				 *  a fast exit in do_IRQ() instead
-	 */
+				 */
 				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
 
 				do
-	{
+				{
 
 	      		asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
 cio_wakeup:
@@ -1838,13 +1838,13 @@
 
 				*(__u32 *)__LC_SYNC_IO_WORD = 0;
 
-	} /* endif */
+			} /* endif */
 
 			ret = 0;
 			break;
-                  	
-		case 1 :            /* status pending */
 
+		case 1 :            /* status pending */
+	
 			ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
 
 			/*
@@ -1888,14 +1888,14 @@
 				ret                         = -ENODEV;
 				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
 				ioinfo[irq]->ui.flags.oper  = 0;
-	}
-	else
-	{
+			}
+			else
+			{
 				ret                         = -EIO;
 				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
 				ioinfo[irq]->ui.flags.oper  = 1;
 
-	} /* endif */
+			} /* endif */
 
 			break;
 
@@ -1914,32 +1914,32 @@
 		if ( sync_isc_locked )
 		{
 			disable_cpu_sync_isc( irq );
-   	
+  	
 			sync_isc_locked              = 0;    // local setting
 			ioinfo[irq]->ui.flags.syncio = 0;    // global setting
   	
 			spin_unlock_irqrestore( &sync_isc, psw_flags);
-
+  	
 		} /* endif */
-			
+
 	} /* endif */
 
 	return( ret );
 }
 
 
-		/*
+/*
  * do_IRQ() handles all normal I/O device IRQ's (the special
  *          SMP cross-CPU interrupts have their own specific
  *          handlers).
-		 *
+ *
  * Returns: 0 - no ending status received, no further action taken
  *          1 - interrupt handler was called with ending status
-		 */
+ */
 asmlinkage void do_IRQ( struct pt_regs regs,
                         unsigned int   irq,
                         __u32          s390_intparm )
-		{
+{
 #ifdef CONFIG_FAST_IRQ
 	int			ccode;
 	tpi_info_t 	tpi_info;
@@ -1958,15 +1958,15 @@
 		return;	/* this keeps the device boxed ... */
 	}
 
-		/*
+	/*
 	 * take fast exit if CPU is in sync. I/O state
-		 *
+	 *
 	 * Note: we have to turn off the WAIT bit and re-disable
 	 *       interrupts prior to return as this was the initial
 	 *       entry condition to synchronous I/O.
-		 */
+	 */
  	if (    *(__u32 *)__LC_SYNC_IO_WORD )
-		{
+	{
 		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
 
       return;
@@ -1983,9 +1983,9 @@
 
 #ifdef CONFIG_FAST_IRQ
 
-			   /*
+		/*
 		 * more interrupts pending ?
-			    */
+		 */
 		ccode = tpi( &tpi_info );
 
 		if ( ! ccode )
@@ -1993,29 +1993,29 @@
 
 		new_irq     = tpi_info.irq;
 
-			   /*
+		/*
 		 * if the interrupt is for a different irq we
 		 *  release the current irq lock and obtain
 		 *  a new one ...
-			    */
+		 */
 		if ( new_irq != use_irq )
-			   {
+      {
 			s390irq_spin_unlock(use_irq);
          use_irq = new_irq;
 			s390irq_spin_lock(use_irq);
 
-			   } /* endif */
+      } /* endif */
 
 	} while ( 1 );
 
 #endif /*  CONFIG_FAST_IRQ */
 
 	s390irq_spin_unlock(use_irq);
-			
+
 	return;
-			}
+}
 
-				/*
+/*
  * s390_process_IRQ() handles status pending situations and interrupts
  *
  * Called by : do_IRQ()             - for "real" interrupts
@@ -2025,7 +2025,7 @@
  *
  * Returns: 0 - no ending status received, no further action taken
  *          1 - interrupt handler was called with ending status
-				 */
+ */
 int s390_process_IRQ( unsigned int irq )
 {
 	int                    ccode;      /* cond code from tsch() operation */
@@ -2056,18 +2056,18 @@
 	else
 	{
 		action = ioinfo[irq]->irq_desc.action;
-
-		} /* endif */
+	
+  	} /* endif */
 
 #ifdef CONFIG_DEBUG_IO
-      /*
+	/*
 	 * It might be possible that a device was not-oper. at the time
 	 *  of free_irq() processing. This means the handler is no longer
 	 *  available when the device possibly becomes ready again. In
 	 *  this case we perform delayed disable_subchannel() processing.
-		 */
+	 */
 	if ( action == NULL )
-		{
+	{
 		if ( !ioinfo[irq]->ui.flags.d_disable )
 		{
 			printk( KERN_CRIT"s390_process_IRQ(%04X) "
@@ -2077,14 +2077,15 @@
 			        ioinfo[irq]->devstat.devno);
 
 		} /* endif */
+
 	} /* endif */
 #endif
 
-      /*
+	/*
 	 * retrieve the i/o interrupt information (irb),
 	 *  update the device specific status information
 	 *  and possibly call the interrupt handler.
-       *
+	 *
 	 * Note 1: At this time we don't process the resulting
 	 *         condition code (ccode) from tsch(), although
 	 *         we probably should.
@@ -2097,75 +2098,72 @@
 	 *         parameter relates to it. If a halt function was
 	 *         issued for an idle device, the intparm must not
 	 *         be taken from lowcore, but from the devstat area.
-       */
+	 */
 	ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
 
 	//
 	// We must only accumulate the status if the device is busy already
 	//
 	if ( ioinfo[irq]->ui.flags.busy )
-				{
-		ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
-		ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
-			}
-			else
-			{
-		ioinfo[irq]->devstat.dstat  = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
-		ioinfo[irq]->devstat.cstat  = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
-
-		ioinfo[irq]->devstat.flag   = 0;   // reset status flags
-
-      } /* endif */
-
-	ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
-
-	if ( ioinfo[irq]->ui.flags.busy)
 	{
-		ioinfo[irq]->devstat.intparm  = ioinfo[irq]->u_intparm;
+		ioinfo[irq]->devstat.dstat   |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
+		ioinfo[irq]->devstat.cstat   |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
+                ioinfo[irq]->devstat.intparm  = ioinfo[irq]->u_intparm; 
+                                                                        
+	}
+	else
+	{
+		ioinfo[irq]->devstat.dstat    = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
+		ioinfo[irq]->devstat.cstat    = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
 
+		ioinfo[irq]->devstat.flag     = 0;   // reset status flags
+		ioinfo[irq]->devstat.intparm  = 0; 
+                                                                        
 	} /* endif */
 
-		/*
+	ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
+
+	/*
 	 * reset device-busy bit if no longer set in irb
-		 */
+	 */
 	if (   (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY                   )
 	    && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
-		{
+	{
 		ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY;
 
 	} /* endif */
 
-			/*
+	/*
 	 * Save residual count and CCW information in case primary and
 	 *  secondary status are presented with different interrupts.
-			 */
+	 */
 	if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl
 	           & (   SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) )
-			{
+	{
 		ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
 		ioinfo[irq]->devstat.cpa    = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
 
 #ifdef CONFIG_DEBUG_IO
-      if ( irq != cons_dev )
-         printk( "s390_process_IRQ( %04X ) : "
-                 "residual count from irb after tsch() %d\n",
-                 irq, ioinfo[irq]->devstat.rescnt );
+		if ( irq != cons_dev )
+			printk( "s390_process_IRQ( %04X ) : "
+			        "residual count from irb after tsch() %d\n",
+			        irq, ioinfo[irq]->devstat.rescnt );
 #endif
 
 	} /* endif */
 
 	irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc;
 
-				//
+	//
 	// check for any kind of channel or interface control check but don't
 	//  issue the message for the console device
-				//
+	//
 	if (    (ioinfo[irq]->devstat.ii.irb.scsw.cstat
 	            & (  SCHN_STAT_CHN_DATA_CHK
 	               | SCHN_STAT_CHN_CTRL_CHK
 	               | SCHN_STAT_INTF_CTRL_CHK )       )
 	     && (irq != cons_dev                         ) )
-				{
+	{
 		printk( "Channel-Check or Interface-Control-Check "
 		        "received\n"
 		        " ... device %04X on subchannel %04X, dev_stat "
@@ -2187,22 +2185,22 @@
 		             ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt;
 		ioinfo[irq]->devstat.flag |=
 		             DEVSTAT_FLAG_SENSE_AVAIL;
-
+                  	
 		sdevstat = sizeof( devstat_t);
 
 #ifdef CONFIG_DEBUG_IO
-      if ( irq != cons_dev )
-         printk( "s390_process_IRQ( %04X ) : "
-                 "concurrent sense bytes avail %d\n",
-                 irq, ioinfo[irq]->devstat.scnt );
+		if ( irq != cons_dev )
+			printk( "s390_process_IRQ( %04X ) : "
+			        "concurrent sense bytes avail %d\n",
+			        irq, ioinfo[irq]->devstat.scnt );
 #endif
-			}
-			else
-			{
+	}
+	else
+	{
 		/* don't copy the sense data area ! */
 		sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
 
-			} /* endif */
+	} /* endif */
 
 	switch ( irb_cc ) {
 	case 1:      /* status pending */
@@ -2311,7 +2309,7 @@
 				        sizeof( devstat_t) );
 
 				s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-				s_ccw->cda      = (char *)virt_to_phys( ioinfo[irq]->sense_data);
+				s_ccw->cda      = (__u32)virt_to_phys( ioinfo[irq]->sense_data );
 				s_ccw->count    = SENSE_MAX_COUNT;
 				s_ccw->flags    = CCW_FLAG_SLI;
 
@@ -2995,8 +2993,8 @@
 //
 // Output : none
 //
-void VM_virtual_device_info( unsigned int  devno,
-                             senseid_t    *ps )
+void VM_virtual_device_info( unsigned int devno,
+                             senseid_t *ps )
 {
 	diag210_t  diag_data;
 	int        ccode;
@@ -3222,7 +3220,7 @@
 
 			error = 1;
 
-		break;
+			break;
 
 		} /* endswitch */
 
@@ -3322,19 +3320,19 @@
    }
 
 	if ( ioinfo[irq]->ui.flags.oper == 0 )
-		{
+	{
 		return( -ENODEV );
 
 	} /* endif */
 
-				/*
+	/*
 	 * Before playing around with irq locks we should assure
 	 *   running disabled on (just) our CPU. Sync. I/O requests
     *   also require to run disabled.
 	 *
 	 * Note : as no global lock is required, we must not use
 	 *        cli(), but __cli() instead.  	
-				 */
+	 */
 	__save_flags(flags);
 	__cli();
 
@@ -3357,11 +3355,11 @@
 	if ( !ret )
 	{
 		if ( ! *buffer )
-	{
+		{
 			rdc_buf  = kmalloc( length, GFP_KERNEL);
-   }
-	else
-	{
+		}
+		else
+		{
 			rdc_buf = *buffer;
 
 		} /* endif */
@@ -3375,7 +3373,7 @@
 			do
 			{
 				rdc_ccw->cmd_code = CCW_CMD_RDC;
-				rdc_ccw->cda      = (char *)virt_to_phys( rdc_buf );
+				rdc_ccw->cda      = (__u32)virt_to_phys( rdc_buf );
 				rdc_ccw->count    = length;
 				rdc_ccw->flags    = CCW_FLAG_SLI;
 
@@ -3398,21 +3396,21 @@
 		} /* endif */
 
 		if ( !retry )
-			{
+		{
 			ret = -EBUSY;
 
 		} /* endif */
 
 		__restore_flags(flags);
 
-				/*
+		/*
 		 * on success we update the user input parms
-				 */
+		 */
 		if ( !ret )
 		{
 			*buffer = rdc_buf;
 
-			} /* endif */
+		} /* endif */
 
 		if ( emulated )
 		{
@@ -3425,11 +3423,11 @@
 	return( ret );
 }
 
-		/*
+/*
  *  Read Configuration data
-		 */
+ */
 int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
-		{
+{
 	unsigned long flags;
 	int           ciw_cnt;
 
@@ -3439,7 +3437,7 @@
 	if ( (irq > highest_subchannel) || (irq < 0 ) )
 	{
 		return( -ENODEV );
-				}
+	}
 	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		return( -ENODEV);
@@ -3456,12 +3454,12 @@
 	{
 		return( -EOPNOTSUPP );
 
-   } /* endif */
+	} /* endif */
 
-			/*
+	/*
 	 * scan for RCD command in extended SenseID data
-			 */
-
+	 */
+	
 	for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
 	{
 		if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
@@ -3473,15 +3471,16 @@
 			{
 				found = 1;
 
-	} /* endif */
+			} /* endif */
 
       	break;
+
       } /* endif */
 
    } /* endfor */
 
 	if ( found )
-{
+	{
 		devstat_t  devstat;  /* inline device status area */
 		devstat_t *pdevstat;
 		int        ioflags;
@@ -3506,9 +3505,9 @@
 				emulated = 1;
 
 			} /* endif */
-				}
+		}
 		else
-				{
+		{
 			pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
 
 		} /* endif */
@@ -3519,9 +3518,9 @@
 			{
 				rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
 				                   GFP_KERNEL);
-				}
+			}
 			else
-				{
+			{
 				rcd_buf = alloc_bootmem( ioinfo[irq]->senseid.ciw[ciw_cnt].count);
 
    		} /* endif */
@@ -3530,18 +3529,18 @@
 			{
 				ret = -ENOMEM;	
 
-				} /* endif */
+			} /* endif */
 
 			if ( !ret )
 			{
 				memset( rcd_buf,
 				        '\0',
 				        ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-
+       	
 				do
-			{
+				{
 					rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
-					rcd_ccw->cda      = (char *)virt_to_phys( rcd_buf );
+					rcd_ccw->cda      = (__u32)virt_to_phys( rcd_buf );
 					rcd_ccw->count    = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
 					rcd_ccw->flags    = CCW_FLAG_SLI;
 
@@ -3552,13 +3551,13 @@
 						ioflags = DOIO_WAIT_FOR_INTERRUPT
 						          | DOIO_VALID_LPM    					
 						          | DOIO_DONT_CALL_INTHDLR;
-		}
-		else
-		{
+					}
+					else
+					{
 						ioflags =   DOIO_WAIT_FOR_INTERRUPT
 						          | DOIO_DONT_CALL_INTHDLR;
-
-		} /* endif */
+						             					
+					} /* endif */
 
 					ret = s390_start_IO( irq,
 					                     rcd_ccw,
@@ -3575,12 +3574,12 @@
       	                                   | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
 	               {
    	               retry = 0;  // we got it ...
-	}
-	else
-	{
+      	         }
+         	      else
+            	   {
                	   retry--;    // try again ...
 
-	} /* endif */
+	               } /* endif */
 
    	            break;
 
@@ -3612,9 +3611,9 @@
 				if ( init_IRQ_complete )
 				{
 					kfree( rcd_buf );
-		}
-		else
-		{
+				}
+				else
+				{
 					free_bootmem( (unsigned long)rcd_buf,
 					              ioinfo[irq]->senseid.ciw[ciw_cnt].count);
 
@@ -3624,7 +3623,7 @@
 
 			*buffer = NULL;
 			*length = 0;
-
+    	
 		} /* endif */
 
 		if ( emulated )
@@ -3645,7 +3644,6 @@
 	return( get_dev_info_by_irq( irq, pdi));
 }
 
-
 static int __inline__ get_next_available_irq( ioinfo_t *pi)
 {
 	int ret_val;
@@ -3667,7 +3665,7 @@
 			if ( pi == NULL )
 			{
 				ret_val = -ENODEV;
-			break;
+				break;
 			}
 
 		} /* endif */
@@ -3696,7 +3694,7 @@
 		else
 		{
 			ret_irq = -ENODEV;
-
+   	
 		} /* endif */
 	}
 	else
@@ -3820,8 +3818,8 @@
 			     && ioinfo[i]->schib.pmcw.dev == devno )
 			{
 
-					pdi->irq    = i;
-					pdi->devno  = devno;
+				pdi->irq   = i;
+				pdi->devno = devno;
 
 				if (    ioinfo[i]->ui.flags.oper
                  && !ioinfo[i]->ui.flags.unknown )
@@ -3845,7 +3843,7 @@
 				else
 				{
 					pdi->status = DEVSTAT_NOT_OPER;
-
+	
 					memset( &(pdi->sid_data),
                        '\0',
                        sizeof( senseid_t));
@@ -3858,7 +3856,7 @@
 					pdi->status |= DEVSTAT_DEVICE_OWNED;
 
 				rc = 0; /* found */
-			break;
+				break;
 
 			} /* endif */
 
@@ -3889,7 +3887,7 @@
 			} /* endif */
 
 		} /* endfor */
-
+	
 	} /* endif */
 
 	return( rc);
@@ -3903,7 +3901,7 @@
 	     || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
 	{
 		return -1;
-
+	
 	} /* endif */
 
 	/*
@@ -3955,7 +3953,7 @@
 			 *  single I/O during boot (IPL) processing.
 			 */
 			spin_lock_irqsave( &sync_isc, psw_flags);
-
+ 	
 			ret = enable_cpu_sync_isc( irq);
 
 			if ( ret )
@@ -3964,7 +3962,7 @@
 			}
 			else
 			{
-				ioinfo[irq]->ui.flags.syncio = 1; // global
+				ioinfo[irq]->ui.flags.syncio  = 1; // global
 				ioinfo[irq]->ui.flags.unknown = 0;
 
 				memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
@@ -4022,7 +4020,7 @@
 			free_irq( irq, &devstat );
 
 		} /* endif */
-
+		
 	} /* endif */
 
 }
@@ -4063,13 +4061,14 @@
 	{
 		ret = s390_validate_subchannel( irq, 0);
 
-		irq++;
-
+		if ( ret != -ENXIO)
+			irq++;
+	
   	} while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) );
 
-	highest_subchannel = --irq;
+	highest_subchannel = (--irq);
 
-	printk( "\nHighest subchannel number detected: %u\n",
+	printk( "Highest subchannel number detected (hex) : %04X\n",
 	        highest_subchannel);
 }
 
@@ -4136,7 +4135,6 @@
 		{
 			if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 			{	
-
 				if ( !init_IRQ_complete )
 				{
 					ioinfo[irq] =
@@ -4156,7 +4154,7 @@
 			           sizeof( schib_t));
 				ioinfo[irq]->irq_desc.status  = IRQ_DISABLED;
 				ioinfo[irq]->irq_desc.handler = &no_irq_type;
-
+			
 				/*
 				 * We have to insert the new ioinfo element
 				 *  into the linked list, either at its head,
@@ -4191,14 +4189,14 @@
 							ioinfo[irq]->prev = pi;
 							pi->next->prev    = ioinfo[irq];
 							pi->next          = ioinfo[irq];
-			break;
-
+							break;
+						
 						} /* endif */
 
 						pi = pi->next;
 
 					} while ( 1 );
-
+      	
 				} /* endif */
 
 			} /* endif */
@@ -4218,7 +4216,7 @@
 			        ioinfo[irq]->schib.pmcw.pam,
 			        ioinfo[irq]->schib.pmcw.pom);
 
-/*
+			/*
 			 * initialize ioinfo structure
 			 */
 			ioinfo[irq]->irq             = irq;
@@ -4232,9 +4230,9 @@
 
 			/*
 			 * We should have at least one CHPID ...
- */
+			 */
 			if ( ioinfo[irq]->opm )
-{
+			{
 				/*
 				 * We now have to initially ...
 				 *  ... set "interruption sublass"
@@ -4260,15 +4258,15 @@
 				     && ( ioinfo[irq]->opm != 0x04 )
 				     && ( ioinfo[irq]->opm != 0x02 )
 				     && ( ioinfo[irq]->opm != 0x01 ) )
-  {
+				{
 					ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
 
-  } /* endif */
+				} /* endif */
 
 				retry = 5;
 
 				do
-	{
+				{
 					ccode2 = msch_err( irq, &ioinfo[irq]->schib);
 
 					switch (ccode2) {
@@ -4280,7 +4278,7 @@
 						ioinfo[irq]->ui.flags.consns = 1;
 						ret                          = 0;
 						break;
-
+      	
 					case 1:  // status pending
 						//
 						// How can we have a pending status as
@@ -4293,12 +4291,12 @@
 						retry--;
 						ret = -EIO;
 						break;
-
+   	
 					case 2:  // busy
-	/*
+						/*
 						 * we mark it not-oper as we can't
 						 *  properly operate it !
-	 */
+						 */
 						ioinfo[irq]->ui.flags.oper = 0;
 						tod_wait( 100);	/* allow for recovery */
 						retry--;
@@ -4315,39 +4313,39 @@
 #define PGMCHK_OPERAND_EXC      0x15
 
 						if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
-    {
+						{
 							/*
 							 * re-issue the modify subchannel without trying to
 							 *  enable the concurrent sense facility
 							 */
 							ioinfo[irq]->schib.pmcw.csense = 0;
-
+   	
 							ccode2 = msch_err( irq, &ioinfo[irq]->schib);
 
 							if ( ccode2 != 0 )
-    {
+							{
 								printk( " ... msch() (2) failed with CC = %X\n",
 								        ccode2 );
 								ioinfo[irq]->ui.flags.oper = 0;
 								ret                        = -EIO;
-    }
-    else
-    {
+							}
+							else
+							{
 								ioinfo[irq]->ui.flags.oper   = 1;
 								ioinfo[irq]->ui.flags.consns = 0;
 								ret                          = 0;
 
-    } /* endif */
-    }
-    else
-    {
+							} /* endif */
+						}
+						else
+						{
 							printk( " ... msch() (1) failed with CC = %X\n",
 							        ccode2);
 							ioinfo[irq]->ui.flags.oper = 0;
 							ret                        = -EIO;
 
-    } /* endif */
-
+						} /* endif */
+   	
 						retry  = 0;
 						break;
 
@@ -4356,13 +4354,13 @@
 				} while ( ccode2 && retry );
 
 				if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) )
-    {
+				{
 					printk( " ... msch() retry count for "
 					        "subchannel %04X exceeded, CC = %d\n",
 					        irq,
 					        ccode2);
 
-    } /* endif */
+				} /* endif */
 			}
 			else
 			{
@@ -4373,19 +4371,18 @@
 			} /* endif */
 		}
 		else
-    {
+		{
 			ret = -ENODEV;
 
-    } /* endif */
+		} /* endif */
 	}
 	else
 	{
-		
 		ret = -ENXIO;
 
-  } /* endif */
+	} /* endif */
 
-  return( ret );
+	return( ret );
 }
 
 /*
@@ -4417,70 +4414,70 @@
 	senseid_t *psid     = sid;/* start with the external buffer */	
 	int        sbuffer  = 0; /* switch SID data buffer */
 
-   if ( (irq > highest_subchannel) || (irq < 0 ) )
-   {
-      return( -ENODEV );
+	if ( (irq > highest_subchannel) || (irq < 0 ) )
+	{
+		return( -ENODEV );
 
-   }
+	}
 	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		return( -ENODEV);
 
-   } /* endif */
+	} /* endif */
 
-   if ( ioinfo[irq]->ui.flags.oper == 0 )
-   {
-      return( -ENODEV );
+	if ( ioinfo[irq]->ui.flags.oper == 0 )
+	{
+		return( -ENODEV );
 
-   } /* endif */
+	} /* endif */
 
-		if ( !ioinfo[irq]->ui.flags.ready )
-       {
+	if ( !ioinfo[irq]->ui.flags.ready )
+	{
 
 		pdevstat = &devstat;
 
-       /*
+		/*
 		 * Perform SENSE ID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
 		 *  requests and evaluate the devstat area on return therefore
 		 *  we don't need a real I/O handler in place.
-        */
+		 */
 		irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
 
 		if ( irq_ret == 0 )
 			inlreq = 1;
-   }
-   else
-   {
+	}
+	else
+	{
 		inlreq   = 0;
 		irq_ret  = 0;
 		pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
 
-   } /* endif */
+  	} /* endif */
 
 	if ( irq_ret == 0 )
-{
+   {
       int i;
 
 		s390irq_spin_lock( irq);
 
 		// more than one path installed ?
 		if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-{
+		{
 			sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
 			sense_ccw[0].cda      = 0;
 			sense_ccw[0].count    = 0;
 			sense_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
 
 			sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[1].cda      = (char *)virt_to_phys( psid );
+			sense_ccw[1].cda      = (__u32)virt_to_phys( sid );
 			sense_ccw[1].count    = sizeof( senseid_t);
 			sense_ccw[1].flags    = CCW_FLAG_SLI;
 		}
 		else
 		{
 			sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[0].cda      = (char *)virt_to_phys( psid );
+			sense_ccw[0].cda      = (__u32)virt_to_phys( sid );
 			sense_ccw[0].count    = sizeof( senseid_t);
 			sense_ccw[0].flags    = CCW_FLAG_SLI;
 
@@ -4496,7 +4493,7 @@
 				domask &= lpm;
 
 			if ( domask )
-		{
+			{
 				psid->cu_type    = 0xFFFF;  /* initialize fields ... */
 				psid->cu_model   = 0;
 				psid->dev_type   = 0;
@@ -4504,14 +4501,14 @@
 
 				retry            = 5;  /* retry count    */
 				io_retry         = 1;  /* enable retries */
-   	
+
 				/*
 				 * We now issue a SenseID request. In case of BUSY,
 				 *  STATUS PENDING or non-CMD_REJECT error conditions
 				 *  we run simple retries.
 				 */
 				do
-	{
+				{
 					memset( pdevstat, '\0', sizeof( devstat_t) );
 
 					irq_ret = s390_start_IO( irq,
@@ -4533,9 +4530,9 @@
 					//
 
 					if ( psid->cu_type  == 0xFFFF )
-	{
+					{
 						if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-		{
+						{
 #ifdef CONFIG_DEBUG_IO
 							printk( "SenseID : device %04X on "
 							        "Subchannel %04X "
@@ -4548,14 +4545,14 @@
 						} /* endif */
 
 						if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-			{
+						{
 							/*
 							 * if the device doesn't support the SenseID
 							 *  command further retries wouldn't help ...
 							 */
 							if (  pdevstat->ii.sense.data[0]
 							    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) )
-			{
+							{
 #ifdef CONFIG_DEBUG_IO
 								printk( "SenseID : device %04X on "
 								        "Subchannel %04X "
@@ -4565,10 +4562,10 @@
 								        irq);
 #endif
 								io_retry = 1;
-		}
+							}
 #ifdef CONFIG_DEBUG_IO
-		else
-		{
+							else
+							{
 								printk( "SenseID : UC on "
 								        "dev %04X, "
 								        "retry %d, "
@@ -4590,12 +4587,12 @@
 								        pdevstat->ii.sense.data[6],
 								        pdevstat->ii.sense.data[7]);
 
-		} /* endif */
+							} /* endif */
 #endif
-	}
+						}
 						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
 					             || ( irq_ret        == -ENODEV         ) )
-	{
+						{
 #ifdef CONFIG_DEBUG_IO
 							printk( "SenseID : path %02X for "
 							        "device %04X on "
@@ -4608,8 +4605,8 @@
 
 							io_retry          = 0;
 							ioinfo[irq]->opm &= ~domask;
-
-}
+      	
+						}
 #ifdef CONFIG_DEBUG_IO
 						else if (     (pdevstat->flag !=
 						                    (   DEVSTAT_START_FUNCTION
@@ -4630,11 +4627,11 @@
 
 						} /* endif */
 #endif
-	}
+					}
 					else   // we got it ...
-	{
+					{
 						if ( !sbuffer )	// switch buffers
-	{
+						{
 							/*
 							 * we report back the
 							 *  first hit only
@@ -4642,14 +4639,14 @@
 							psid = &isid;
 
 							if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-      {
-								sense_ccw[1].cda = (char *)virt_to_phys( psid );
-      }
-      else
-      {
-								sense_ccw[0].cda = (char *)virt_to_phys( psid );
+							{
+								sense_ccw[1].cda = (__u32)virt_to_phys( psid );
+							}
+							else
+							{
+								sense_ccw[0].cda = (__u32)virt_to_phys( psid );
 
-      } /* endif */
+							} /* endif */
 
 							/*
 							 * if just the very first
@@ -4662,35 +4659,35 @@
 
 							sbuffer = 1;
 
-	} /* endif */
+						} /* endif */
 
 					   if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
-{
+						{
 							ioinfo[irq]->ui.flags.esid = 1;
-
+       							
 						} /* endif */
 
 						io_retry = 0;
-
+						
 					} /* endif */
 
 					if ( io_retry )
-            {
+					{
 						retry--;
-	
+
 						if ( retry == 0 )
 						{
 							io_retry = 0;
 
-            } /* endif */
-
+						} /* endif */
+      	
 					} /* endif */
-
+	
 				} while ( (io_retry) );
 
  			} /* endif - domask */
 
-      } /* endfor */
+		} /* endfor */
 
 		s390irq_spin_unlock( irq);
 
@@ -4713,7 +4710,7 @@
 		} /* endif */
 
 		if ( sid->cu_type == 0xFFFF )
-{
+		{
 			/*
 			 * SenseID CU-type of 0xffff indicates that no device
 			 *  information could be retrieved (pre-init value).
@@ -4733,10 +4730,10 @@
 		/*
 		 * Issue device info message if unit was operational .
 		 */
-		if ( ioinfo[irq]->ui.flags.unknown )
-	{
+		if ( !ioinfo[irq]->ui.flags.unknown )
+		{
 			if ( sid->dev_type != 0 )
-      {
+			{
 				printk( "SenseID : device %04X reports: CU  Type/Mod = %04X/%02X,"
 				        " Dev Type/Mod = %04X/%02X\n",
 				        ioinfo[irq]->schib.pmcw.dev,
@@ -4746,18 +4743,18 @@
 				        sid->dev_model);
 			}
 			else
-         {
+			{
 				printk( "SenseID : device %04X reports:"
 				        " Dev Type/Mod = %04X/%02X\n",
 				        ioinfo[irq]->schib.pmcw.dev,
 				        sid->cu_type,
 				        sid->cu_model);
 
-         } /* endif */
+			} /* endif */
 
-	} /* endif */
+		} /* endif */
 
-		if ( ioinfo[irq]->ui.flags.unknown )
+		if ( !ioinfo[irq]->ui.flags.unknown )
 			irq_ret = 0;
 		else
 			irq_ret = -ENODEV;
@@ -4774,7 +4771,7 @@
 	cc = stsch( irq, &ioinfo[irq]->schib );
 
 	if ( !cc )
-      {
+	{
 		ioinfo[irq]->schib.pmcw.mp = 1;     /* multipath mode */
 
 		cc = msch( irq, &ioinfo[irq]->schib );
@@ -4812,17 +4809,17 @@
 	if ( ccode )
 	{
 		ret = -ENODEV;
-}
+	}
 	else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 )
 	{
-/*
+		/*
 		 * no error, just not required for single path only devices
- */
+		 */	
 		ioinfo[irq]->ui.flags.pgid_supp = 0;
 		ret = 0;
 	}
 	else
-{
+	{
 		int    i;
 		pgid_t pgid;
 		__u8   dev_path;
@@ -4833,16 +4830,16 @@
 		                   & ioinfo[irq]->schib.pmcw.pom;
 
 		if ( usermask )
-	{
+		{
 			dev_path = usermask;
-	}
-	else
-	{
+		}
+		else
+		{
 			dev_path = ioinfo[irq]->opm;
 
-	} /* endif */
+		} /* endif */
 
-   	/*
+		/*
 		 * let's build a path group ID if we don't have one yet
 		 */
 		if ( ioinfo[irq]->ui.flags.pgid == 0)
@@ -4854,7 +4851,7 @@
 
 			ioinfo[irq]->ui.flags.pgid  = 1;
 
-		} /* endif */
+		} /* endif */     		
 
 		memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t));
 
@@ -4865,7 +4862,7 @@
 			domask = dev_path & pathmask;
 
 			if ( domask )
-				{
+			{
 				ret = s390_SetPGID( irq, domask, &pgid );
 
 				/*
@@ -4879,30 +4876,30 @@
 				if ( ret == -EOPNOTSUPP && first )
 				{
 					*(int *)&pgid = 0;
-
+					
 					ret   = s390_SensePGID( irq, domask, &pgid);
 					first = 0;
-			
+
 					if ( ret == 0 )
 					{
-			/*
+						/*
 						 * Check whether we retrieved
 						 *  a reasonable PGID ...
-			 */
+						 */	
 						if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED )
-				{
+						{
 							memcpy( &(ioinfo[irq]->pgid),
 							        &pgid,
 							        sizeof(pgid_t) );
-		}
+						}
 						else // ungrouped or garbage ...
-				{
+						{
 							ret = -EOPNOTSUPP;
 
 						} /* endif */
-				}
+					}
 					else
-				{
+					{
 						ioinfo[irq]->ui.flags.pgid_supp = 0;
 
 #ifdef CONFIG_DEBUG_IO
@@ -4924,18 +4921,18 @@
 						        " support path grouping\n",
 						        irq,
 						        ioinfo[irq]->schib.pmcw.dev);
-						
+
 #endif
 
 					ioinfo[irq]->ui.flags.pgid_supp = 0;
 
 				} /* endif */
-      	
-				} /* endif */
+
+			} /* endif */
 
 		} /* endfor */
 
-			} /* endif */
+	} /* endif */
 
 	return ret;
 #else
@@ -4943,14 +4940,14 @@
 #endif
 }
 
-			/*
+/*
  * s390_SetPGID
  *
  * Set Path Group ID
-			 *
-			 */
+ *
+ */
 int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
-			{
+{
 	ccw1_t     spid_ccw[2]; /* ccw area for SPID command */
 	devstat_t  devstat;     /* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
@@ -4966,7 +4963,7 @@
 
 	}
 	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-			{
+	{
 		return( -ENODEV);
 
 	} /* endif */
@@ -5001,7 +4998,7 @@
 	} /* endif */
 
 	if ( irq_ret == 0 )
-				   {
+	{
 		s390irq_spin_lock( irq);
 
 		spid_ccw[0].cmd_code = 0x5B;	/* suspend multipath reconnect */
@@ -5010,16 +5007,16 @@
 		spid_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
 
 		spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
-		spid_ccw[1].cda      = (char *)virt_to_phys( pgid );
+		spid_ccw[1].cda      = (__u32)virt_to_phys( pgid );
 		spid_ccw[1].count    = sizeof( pgid_t);
 		spid_ccw[1].flags    = CCW_FLAG_SLI;
 
 		pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
 
-						/*
+		/*
 		 * We now issue a SenseID request. In case of BUSY
 		 *  or STATUS PENDING conditions we retry 5 times.
-						 */
+		 */
 		do
 		{
 			memset( pdevstat, '\0', sizeof( devstat_t) );
@@ -5049,7 +5046,7 @@
 
 				if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
 				                         | DEVSTAT_FINAL_STATUS   ) )
-						{
+				{
 					retry = 0;	// successfully set ...
 				}
 				else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
@@ -5106,28 +5103,28 @@
 					        ioinfo[irq]->schib.pmcw.dev,
 					        irq);
 
-					retry  = 0;
+					retry = 0;
 
 				} /* endif */
 			}
 			else if ( irq_ret != -ENODEV )
-         {
+			{
 				retry--;
 			}
 			else
 			{
 				retry = 0;
 
-         } /* endif */
+			} /* endif */
 
 		} while ( retry > 0 );
 
 		s390irq_spin_unlock( irq);
 
-   /*
+		/*
 		 * If we installed the irq action handler we have to
 		 *  release it too.
-    */
+		 */
 		if ( inlreq )
 			free_irq( irq, pdevstat);
 
@@ -5146,12 +5143,12 @@
 int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
 {
 	ccw1_t     snid_ccw;    /* ccw area for SNID command */
-   devstat_t  devstat;     /* required by request_irq() */
+	devstat_t  devstat;     /* required by request_irq() */
 	devstat_t *pdevstat = &devstat;
 
-   int        irq_ret = 0; /* return code */
-   int        retry   = 5; /* retry count */
-   int        inlreq  = 0; /* inline request_irq() */
+	int        irq_ret = 0; /* return code */
+	int        retry   = 5; /* retry count */
+	int        inlreq  = 0; /* inline request_irq() */
 
 	if ( (irq > highest_subchannel) || (irq < 0 ) )
 	{
@@ -5175,9 +5172,9 @@
 		/*
 		 * Perform SENSE ID command processing. We have to request device
 		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
-       *  requests and evaluate the devstat area on return therefore
-       *  we don't need a real I/O handler in place.
-       */
+		 *  requests and evaluate the devstat area on return therefore
+		 *  we don't need a real I/O handler in place.
+		 */
 		irq_ret = request_irq( irq,
 		                       init_IRQ_handler,
 		                       0,
@@ -5195,11 +5192,11 @@
 	} /* endif */
 
 	if ( irq_ret == 0 )
-   {
+	{
 		s390irq_spin_lock( irq);
 
 		snid_ccw.cmd_code = CCW_CMD_SENSE_PGID;
-		snid_ccw.cda      = (char *)virt_to_phys( pgid );
+		snid_ccw.cda      = (__u32)virt_to_phys( pgid );
 		snid_ccw.count    = sizeof( pgid_t);
 		snid_ccw.flags    = CCW_FLAG_SLI;
 
@@ -5220,7 +5217,7 @@
 			                          | DOIO_DONT_CALL_INTHDLR );
 
 			if ( irq_ret == 0 )
-				{
+			{
 				if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
 				{
 					/*
@@ -5230,7 +5227,7 @@
 					 */
 					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
 					{
-						retry = 0;
+						retry   = 0;
 						irq_ret = -EOPNOTSUPP;
 					}
 					else
@@ -5270,12 +5267,12 @@
 
 					retry = 0;
 
-			}
+				}
 				else
-			{
+				{
 					retry = 0; // success ...
 
-			} /* endif */
+				} /* endif */
 			}
 			else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
 			{
@@ -5296,7 +5293,7 @@
 				        " start_io() reports rc : %d, retrying ...\n",
 				        ioinfo[irq]->schib.pmcw.dev,
 				        irq_ret);
-			retry--;
+				retry--;
 			}
 			else	// -ENODEV ...
 			{
@@ -5320,16 +5317,16 @@
    return( irq_ret );
 }
 
-		/*
+/*
  * s390_do_crw_pending
  *
  * Called by the machine check handler to process CRW pending
  *  conditions. It may be a single CRW, or CRWs may be chained.
  *
  * Note : we currently process CRWs for subchannel source only
-		 */
+ */
 void s390_do_crw_pending( crwe_t *pcrwe )
-		{
+{
 	int irq;
 	int dev_oper = 0;
 	int dev_no   = -1;	
@@ -5340,7 +5337,7 @@
 #endif
 
 	while ( pcrwe != NULL )
-		{
+	{
 		switch ( pcrwe->crw.rsc ) {	
 		case CRW_RSC_SCH :
 
@@ -5364,7 +5361,7 @@
 				if ( ioinfo[irq]->ui.flags.dval )
 					dev_no = ioinfo[irq]->devno;
 
-		} /* endif */
+			} /* endif */
 
 #ifdef CONFIG_DEBUG_CRW
 			printk( "do_crw_pending : subchannel validation - start ...\n");
@@ -5377,19 +5374,19 @@
 #ifdef CONFIG_DEBUG_CRW
 			printk( "do_crw_pending : subchannel validation - done\n");
 #endif
-		/*
+			/*
 			 * After the validate processing
 			 *   the ioinfo control block
 			 *   should be allocated ...
-		 */
+			 */
 			if ( lock )
-		{
+			{
 				s390irq_spin_unlock( irq );
 
 			} /* endif */
 
 #ifdef CONFIG_DEBUG_CRW
-	      if ( ioinfo[irq] != INVALID_STORAGE_AREA )
+			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
 			{
 				printk( "do_crw_pending : ioinfo at %08X\n",
 				        (unsigned)ioinfo[irq]);
@@ -5397,7 +5394,7 @@
 			} /* endif */
 #endif
 
-	      if ( ioinfo[irq] != INVALID_STORAGE_AREA )
+			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
 			{
 				if ( ioinfo[irq]->ui.flags.oper == 0 )
 				{
@@ -5408,15 +5405,15 @@
 					if (    (             dev_oper == 1    )
 					     && ( ioinfo[irq]->nopfunc != NULL ) )
 					{
-                  free_irq( irq,
-						          ioinfo[irq]->irq_desc.action->dev_id );
-						ioinfo[irq]->nopfunc( irq,
-						                      DEVSTAT_DEVICE_GONE );				
 
+						free_irq( irq,
+                                                          ioinfo[irq]->irq_desc.action->dev_id );
+						ioinfo[irq]->nopfunc( irq,
+						    DEVSTAT_DEVICE_GONE );				
 					} /* endif */
-			}
-			else
-			{
+				}
+				else
+				{
 #ifdef CONFIG_DEBUG_CRW
 					printk( "do_crw_pending : device "
 					        "recognition - start ...\n");
@@ -5442,7 +5439,7 @@
 							if ( pdevreg->oper_func != NULL )
 								pdevreg->oper_func( irq, pdevreg );
 
-			} /* endif */
+						} /* endif */
 					}
 					/*
 					 * ... it is and was operational, but
@@ -5453,11 +5450,11 @@
 						ioinfo[irq]->nopfunc( irq,
 						                      DEVSTAT_REVALIDATE );				
 
-		} /* endif */
+					} /* endif */
 
 				} /* endif */
 
-	} /* endif */
+			} /* endif */
 
 			break;
 
@@ -5516,13 +5513,13 @@
 
 /* added by Holger Smolinski for reipl support in reipl.S */
 extern void do_reipl (int);
-void 
+void
 reipl ( int sch )
 {
-        int i;
+	int i;
 
 	for ( i = 0; i < highest_subchannel; i ++ ) {
-	  free_irq ( i, (void*)REIPL_DEVID_MAGIC );
+	    free_irq ( i, (void*)REIPL_DEVID_MAGIC );
 	}
 	do_reipl( 0x10000 | sch );
 }
diff -urN linux-2.2.18-pre20/arch/s390/kernel/s390mach.c linux/arch/s390/kernel/s390mach.c
--- linux-2.2.18-pre20/arch/s390/kernel/s390mach.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/s390mach.c	Mon Dec  3 22:14:16 2001
@@ -4,7 +4,7 @@
  *            currently only channel-reports are supported
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
@@ -20,16 +20,16 @@
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
 
-#define S390_MACHCHK_DEBUG
+#undef S390_MACHCHK_DEBUG
 
-static int __init  s390_machine_check_handler( void * parm );
+static int         s390_machine_check_handler( void * parm );
 static void        s390_enqueue_mchchk( mache_t *mchchk );
 static mache_t    *s390_dequeue_mchchk( void );
 static void        s390_enqueue_free_mchchk( mache_t *mchchk );
 static mache_t    *s390_dequeue_free_mchchk( void );
 static int         s390_collect_crw_info( void );
 
-static struct semaphore   s_sem[2];
+static struct semaphore   s_sem;
 
 static mache_t           *mchchk_queue_head = NULL;
 static mache_t           *mchchk_queue_tail = NULL;
@@ -58,8 +58,7 @@
 	crwe_t  *pcrwe;	 /* CRW buffer element pointer */
 	mache_t *pmache;   /* machine check element pointer */
 
-	init_MUTEX_LOCKED( &s_sem[0] );
-	init_MUTEX_LOCKED( &s_sem[1] );
+	init_MUTEX_LOCKED( &s_sem );
 
 	pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL);
 
@@ -69,7 +68,7 @@
 
 		crw_buffer_anchor = pcrwe;
 
-		for ( i=0; i < MAX_CRW_PENDING; i++)
+		for ( i=0; i < MAX_CRW_PENDING-1; i++)
 		{
 			pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t));
    		pcrwe            = pcrwe->crwe_next;
@@ -108,16 +107,7 @@
 	printk( "init_mach : starting machine check handler\n");
 #endif	
 
-	kernel_thread( s390_machine_check_handler, s_sem, 0);
-
-	/*
-	 * wait for the machine check handler to be ready
-	 */
-#ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : waiting for machine check handler coming up ... \n");
-#endif	
-
-	down( &s_sem[0]);
+	kernel_thread( s390_machine_check_handler, &s_sem, 0);
 
 	ctl_clear_bit( 14, 25 );  // disable damage MCH 	
 #if 1
@@ -145,10 +135,10 @@
  * mchine check pre-processor, collecting the machine check info,
  *  queueing it and posting the machine check handler for processing.
  */
-void __init s390_do_machine_check( void )
+void        s390_do_machine_check( void )
 {
 	int      crw_count;
-   mcic_t   mcic;
+	mcic_t   mcic;
 
 #ifdef S390_MACHCHK_DEBUG
 	printk( "s390_do_machine_check : starting ...\n");
@@ -164,7 +154,7 @@
 
 		if ( crw_count )
 		{
-			up( &s_sem[1] );
+			up( &s_sem );
 
 		} /* endif */
 
@@ -183,7 +173,7 @@
  * machine check handler, dequeueing machine check entries
  *  and processing them
  */
-static int __init s390_machine_check_handler( void *parm)
+static int        s390_machine_check_handler( void *parm)
 {
 	struct semaphore *sem = parm;
 	int               flags;
@@ -191,11 +181,12 @@
 
 	int               found = 0;
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "mach_handler : up\n");
-#endif	
+	/* set name to something sensible */
+        strncpy(current->comm,"kmcheck",15);
+        current->comm[15]=0;
 
-	up( &sem[0] );
+        /* block all signals */
+        sigfillset(&current->blocked);
 
 #ifdef S390_MACHCHK_DEBUG
 	printk( "mach_handler : ready\n");
@@ -207,15 +198,18 @@
 		printk( "mach_handler : waiting for wakeup\n");
 #endif	
 
-		down_interruptible( &sem[1] );
+		down_interruptible( sem );
 
 #ifdef S390_MACHCHK_DEBUG
 		printk( "\nmach_handler : wakeup ... \n");
 #endif	
+		found = 0; /* init ... */
 
 		__save_flags( flags );
 		__cli();
 
+		do {
+
 		pmache = s390_dequeue_mchchk();
 
 		if ( pmache )
@@ -256,18 +250,19 @@
 		}
 		else
 		{
-			found = 0;
 
 			// unconditional surrender ...
 #ifdef S390_MACHCHK_DEBUG
-			printk( "mach_handler : terminated \n");
+			printk( "mach_handler : nothing to do, sleeping\n");
 #endif	
 
 		} /* endif */	
 
+		} while ( pmache );
+
 		__restore_flags( flags );
 
-	} while ( found );
+	} while ( 1 );
 
 	return( 0);
 }
diff -urN linux-2.2.18-pre20/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c
--- linux-2.2.18-pre20/arch/s390/kernel/setup.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/setup.c	Mon Dec  3 22:14:16 2001
@@ -137,7 +137,7 @@
 #ifndef CONFIG_SMP
 void machine_restart(char * __unused)
 {
-  reipl(S390_lowcore.ipl_device); 
+        reipl(S390_lowcore.ipl_device); 
 }
 
 void machine_halt(void)
@@ -145,14 +145,14 @@
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-        }
+}
 
 void machine_power_off(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-        }
+}
 #endif
 
 /*
@@ -177,7 +177,7 @@
 __initfunc(void setup_arch(char **cmdline_p,
         unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
-        static unsigned int smptrap=0;
+        static unsigned int smptrap = 0;
         unsigned long memory_start, memory_end;
         char c, cn, *to, *from;
 
diff -urN linux-2.2.18-pre20/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c
--- linux-2.2.18-pre20/arch/s390/kernel/signal.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/signal.c	Mon Dec  3 22:14:16 2001
@@ -39,7 +39,7 @@
 #define SIGFRAME_COMMON \
 __u8     callee_used_stack[__SIGNAL_FRAMESIZE]; \
 struct sigcontext sc; \
-sigregs sregs; \
+_sigregs sregs; \
 __u8 retcode[S390_SYSCALL_SIZE];
 
 typedef struct 
@@ -79,7 +79,7 @@
 		schedule();
 		if (do_signal(regs, &saveset))
 			return -EINTR;
-	  }
+	}
 }
 
 asmlinkage int
@@ -100,17 +100,17 @@
 	current->blocked = newset;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
-	regs->gprs[2]	= -EINTR;
+	regs->gprs[2] = -EINTR;
 
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(regs, &saveset))
 			return -EINTR;
-	  }
+	}
 }
 
-asmlinkage int
+asmlinkage int 
 sys_sigaction(int sig, const struct old_sigaction *act,
 	      struct old_sigaction *oact)
 {
@@ -126,7 +126,7 @@
 		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
 		__get_user(mask, &act->sa_mask);
 		siginitset(&new_ka.sa.sa_mask, mask);
-	  }
+	}
 
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
@@ -137,22 +137,21 @@
 			return -EFAULT;
 		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-	  }
+	}
 
 	return ret;
 }
 
 asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *) &uss;
 	return do_sigaltstack(uss, uoss, regs->gprs[15]);
 }
 
 
 
 
-static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
 {
 	int err;
 	s390_fp_regs fpregs;
@@ -167,7 +166,7 @@
 	
 }
 
-static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
 {
 	int err;
 	s390_fp_regs fpregs;
@@ -189,13 +188,13 @@
 
 static int
 restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
-		 sigregs *sregs,sigset_t *set)
+		 _sigregs *sregs,sigset_t *set)
 {
 	unsigned int err;
 
 	err=restore_sigregs(regs,sregs);
 	if(!err)
-		err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE);
+		err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
 		return(err);
 }
 
@@ -220,20 +219,20 @@
 {
 
 	if (sigreturn_common(regs,sizeof(sigframe)))
-			goto badframe;
+		goto badframe;
 	return regs->gprs[2];
-		
+
 badframe:
 	force_sig(SIGSEGV, current);
 	return 0;
-		}
+}	
 
 asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
 {
 	rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
 
 	if (sigreturn_common(regs,sizeof(rt_sigframe)))
-			goto badframe;
+		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
 	do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
@@ -279,7 +278,7 @@
 static void *setup_frame_common(int sig, struct k_sigaction *ka,
 			sigset_t *set, struct pt_regs * regs,
 				int frame_size,u16 retcode)
-	{
+{
 	sigframe *frame;
 	int err;
 
@@ -291,7 +290,7 @@
 		err=__put_user(&frame->sregs,&frame->sc.sregs);
 	if(!err)
 
-		err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE);
+		err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
 	if(!err)
 	{
 		regs->gprs[2]=(current->exec_domain
@@ -377,29 +376,29 @@
 
 /*
  * OK, we're invoking a handler
- */
+ */	
 
 static void
 handle_signal(unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
-		{
+{
 	/* Are we from a system call? */
 	if (regs->orig_gpr2 >= 0) {
 		/* If so, check system call restarting.. */
 		switch (regs->gprs[2]) {
-		case -ERESTARTNOHAND:
+			case -ERESTARTNOHAND:
 				regs->gprs[2] = -EINTR;
 				break;
 
-		case -ERESTARTSYS:
+			case -ERESTARTSYS:
 				if (!(ka->sa.sa_flags & SA_RESTART)) {
-				regs->gprs[2] = -EINTR;
-				break;
-			}
+					regs->gprs[2] = -EINTR;
+					break;
+				}
 			/* fallthrough */
-		case -ERESTARTNOINTR:
-			regs->gprs[2] = regs->orig_gpr2;
-			regs->psw.addr -= 2;	      
+			case -ERESTARTNOINTR:
+				regs->gprs[2] = regs->orig_gpr2;
+				regs->psw.addr -= 2;
 		}
 	}
 
@@ -430,7 +429,7 @@
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-int do_signal(struct pt_regs *regs,sigset_t *oldset)
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
 	struct k_sigaction *ka;
@@ -554,9 +553,9 @@
 		if (regs->gprs[2] == -ERESTARTNOHAND ||
 		    regs->gprs[2] == -ERESTARTSYS ||
 		    regs->gprs[2] == -ERESTARTNOINTR) {
-		regs->gprs[2] = regs->orig_gpr2;
+			regs->gprs[2] = regs->orig_gpr2;
 			regs->psw.addr -= 2;
+		}
 	}
-}
 	return 0;
 }
diff -urN linux-2.2.18-pre20/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- linux-2.2.18-pre20/arch/s390/kernel/smp.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/kernel/smp.c	Mon Dec  3 22:14:16 2001
@@ -108,7 +108,7 @@
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-        }
+}
 
 void machine_halt(void)
 {
@@ -125,7 +125,7 @@
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
-        }
+}
 
 void machine_power_off(void)
 {
@@ -248,6 +248,14 @@
 			__flush_tlb();
 			atomic_set(&ec->status, ec_done);
 		        return;
+                case ec_callback: {
+                        ec_callback_parms *cbp;
+                        cbp = (ec_callback_parms *) ec->parms;
+                        atomic_set(&ec->status,ec_executing);
+                        (cbp->callback)(cbp->data);
+                        atomic_set(&ec->status,ec_done);
+                        return;
+                }
                 default:
                 }
                 ec = ec->next;
@@ -463,6 +471,19 @@
         __ctl_clear_bit(cr, bit);
 }
 
+/*
+ * Execute a callback function on all cpus
+ */
+void smp_do_callback_all(void (*callback)(void *), void *data) {
+        ec_callback_parms parms;
+
+        if (atomic_read(&smp_commenced) != 0) {
+                parms.callback = callback;
+                parms.data = data;
+                smp_ext_call_sync_others(ec_callback, &parms);
+        }
+        (callback)(data);
+}
 
 /*
  * Lets check how many CPUs we have.
@@ -573,7 +594,7 @@
         sigp_ccode   ccode;
         int curr_cpu;
         int i;
-        
+
         /* request the 0x1202 external interrupt */
         if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
                 panic("Couldn't request external interrupt 0x1202");
diff -urN linux-2.2.18-pre20/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c
--- linux-2.2.18-pre20/arch/s390/kernel/traps.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/traps.c	Mon Dec  3 22:14:16 2001
@@ -43,134 +43,14 @@
 typedef void pgm_check_handler_t(struct pt_regs *, long);
 pgm_check_handler_t *pgm_check_table[128];
 
-extern pgm_check_handler_t default_trap_handler;
 extern pgm_check_handler_t do_page_fault;
 
-asmlinkage int system_call(void);
-
 static inline void console_verbose(void)
 {
         extern int console_loglevel;
         console_loglevel = 15;
 }
 
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void name(struct pt_regs * regs, long error_code) \
-{ \
-        if (check_for_fixup(regs) == 0) { \
-                tsk->tss.error_code = error_code; \
-                tsk->tss.trap_no = trapnr; \
-                force_sig(signr, tsk); \
-	        die(str,regs,error_code); \
-        } \
-}
-
-
-void page_exception(void);
-
-/* TODO: define these as 'pgm_check_handler_t xxx;'
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void double_fault(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
-asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
-*/
-
-int kstack_depth_to_print = 24;
-
-/*
- * These constants are for searching for possible module text
- * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
-void show_crashed_task_info(void)
-{
-	printk("CPU:    %d\n",smp_processor_id());
-	printk("Process %s (pid: %d, stackpage=%08X)\n",
-                current->comm, current->pid, 4096+(addr_t)current);
-	show_regs(current,NULL,NULL);
-}
-#if 0
-static void show_registers(struct pt_regs *regs)
-{
-        printk("CPU:    %d\nPSW:    %08lx %08lx\n",
-                smp_processor_id(), (unsigned long) regs->psw.mask,
-                (unsigned long) regs->psw.addr);
-        printk("GPRS:\n");
-
-        printk("%08lx  %08lx  %08lx  %08lx\n",
-                regs->gprs[0], regs->gprs[1],
-                regs->gprs[2], regs->gprs[3]);
-        printk("%08lx  %08lx  %08lx  %08lx\n",
-                regs->gprs[4], regs->gprs[5],
-                regs->gprs[6], regs->gprs[7]);
-        printk("%08lx  %08lx  %08lx  %08lx\n",
-                regs->gprs[8], regs->gprs[9],
-                regs->gprs[10], regs->gprs[11]);
-        printk("%08lx  %08lx  %08lx  %08lx\n",
-                regs->gprs[12], regs->gprs[13],
-                regs->gprs[14], regs->gprs[15]);
-        printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
-                current->comm, current->pid, 4096+(unsigned long)current);
-/*
-        stack = (unsigned long *) esp;
-        for(i=0; i < kstack_depth_to_print; i++) {
-                if (((long) stack & 4095) == 0)
-                        break;
-                if (i && ((i % 8) == 0))
-                        printk("\n       ");
-                printk("%08lx ", get_seg_long(ss,stack++));
-        }
-        printk("\nCall Trace: ");
-        stack = (unsigned long *) esp;
-        i = 1;
-        module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
-        module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
-        module_end = module_start + MODULE_RANGE;
-        while (((long) stack & 4095) != 0) {
-                addr = get_seg_long(ss, stack++); */
-                /*
-                 * If the address is either in the text segment of the
-                 * kernel, or in the region which contains vmalloc'ed
-                 * memory, it *may* be the address of a calling
-                 * routine; if so, print it so that someone tracing
-                 * down the cause of the crash will be able to figure
-                 * out the call path that was taken.
-                 */
-/*                if (((addr >= (unsigned long) &_stext) &&
-                     (addr <= (unsigned long) &_etext)) ||
-                    ((addr >= module_start) && (addr <= module_end))) {
-                        if (i && ((i % 8) == 0))
-                                printk("\n       ");
-                        printk("[<%08lx>] ", addr);
-                        i++;
-                }
-        }
-        printk("\nCode: ");
-        for(i=0;i<20;i++)
-                printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip)));
-        printk("\n");
-*/
-}
-#endif
-
-
 spinlock_t die_lock;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -178,22 +58,36 @@
         console_verbose();
         spin_lock_irq(&die_lock);
         printk("%s: %04lx\n", str, err & 0xffff);
-        show_crashed_task_info();
+        show_regs(regs);
         spin_unlock_irq(&die_lock);
         do_exit(SIGSEGV);
 }
 
-int check_for_fixup(struct pt_regs * regs)
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+	do_trap(interruption_code, signr, str, regs); \
+}
+
+static void inline do_trap(long interruption_code, int signr, char *str,
+			   struct pt_regs *regs)
 {
-        if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
-		unsigned long fixup;
-		fixup = search_exception_table(regs->psw.addr);
-		if (fixup) {
+	if (regs->psw.mask & PSW_PROBLEM_STATE) {
+		struct task_struct *tsk = current;
+		tsk->tss.trap_no = interruption_code;
+		force_sig(signr, tsk);
+#ifdef CONFIG_PROCESS_DEBUG
+                printk("User process fault: interruption code 0x%lX\n",
+		       interruption_code);
+                show_regs(regs);
+#endif
+	} else {
+		unsigned long fixup = search_exception_table(regs->psw.addr);
+		if (fixup)
 			regs->psw.addr = fixup;
-			return 1;
-		}
+		else
+			die(str, regs, interruption_code);
 	}
-	return 0;
 }
 
 int do_debugger_trap(struct pt_regs *regs,int signal)
@@ -219,39 +113,16 @@
 	return(FALSE);
 }
 
-asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code)
-{
-        if (check_for_fixup(regs) == 0) {
-                current->tss.error_code = error_code;
-                current->tss.trap_no = error_code;
-                force_sig(SIGSEGV, current); 
-                die("Unknown program exception",regs,error_code);
-        }
-}
-
-DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current)
-DO_ERROR(3, SIGILL, "execute exception", execute_exception, current)
-DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current)
-DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current)
-DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current)
-DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current)
-DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current)
-
-/* need to define
-DO_ERROR( 6, SIGILL,  "invalid operand", invalid_op, current)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
-DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
-DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
-DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
-DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
-*/
-
-#ifdef CONFIG_IEEEFPU_EMULATION
+DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler);
+DO_ERROR(SIGILL,  "privileged operation", privileged_op)
+DO_ERROR(SIGILL,  "execute exception", execute_exception)
+DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
+DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGILL,  "translation exception", translation_exception)
+DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
+DO_ERROR(SIGILL,  "operand exception", operand_exception)
 
-asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
+asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
         __u8 opcode[6];
 	__u16 *location;
@@ -269,6 +140,7 @@
 		if(do_debugger_trap(regs,SIGTRAP))
 			do_sig=1;
 	}
+#ifdef CONFIG_IEEEFPU_EMULATION
         else if (problem_state )
 	{
 		if (opcode[0] == 0xb3) {
@@ -289,20 +161,19 @@
 			do_sig = math_emu_lfpc(opcode, regs);
 		} else
 			do_sig = 1;
-        } else
-		do_sig = 1;
-	if (do_sig) {
-                if (check_for_fixup(regs) == 0) {
-                        current->tss.error_code = error_code;
-                        current->tss.trap_no = 1;
-                        force_sig(SIGILL, current);
-                        die("illegal operation", regs, error_code);
-                }
         }
+#endif 
+	else
+		do_sig = 1;
+	if (do_sig)
+		do_trap(interruption_code, SIGILL, "illegal operation", regs);
         unlock_kernel();
 }
 
-asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
+
+
+#ifdef CONFIG_IEEEFPU_EMULATION
+asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code)
 {
         __u8 opcode[6];
 	__u16 *location;
@@ -314,26 +185,26 @@
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
 		case 0x28: /* LDR Rx,Ry   */
-			math_emu_ldr(opcode);
+			do_sig=math_emu_ldr(opcode);
 			break;
 		case 0x38: /* LER Rx,Ry   */
-			math_emu_ler(opcode);
+			do_sig=math_emu_ler(opcode);
 			break;
 		case 0x60: /* STD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_std(opcode, regs);
+			do_sig=math_emu_std(opcode, regs);
 			break;
 		case 0x68: /* LD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_ld(opcode, regs);
+			do_sig=math_emu_ld(opcode, regs);
 			break;
 		case 0x70: /* STE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_ste(opcode, regs);
+			do_sig=math_emu_ste(opcode, regs);
 			break;
 		case 0x78: /* LE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_le(opcode, regs);
+			do_sig=math_emu_le(opcode, regs);
 			break;
 		default:
 			do_sig = 1;
@@ -341,25 +212,22 @@
                 }
         } else
 		do_sig = 1;
-	if (do_sig) {
-                if (check_for_fixup(regs) == 0) {
-                        current->tss.error_code = error_code;
-                        current->tss.trap_no = 1;
-                        force_sig(SIGILL, current);
-                        die("illegal operation", regs, error_code);
-                }
-        }
+        if (do_sig)
+                do_trap(interruption_code, SIGILL, "specification exception", regs);
         unlock_kernel();
 }
+#else
+DO_ERROR(SIGILL, "specification exception", specification_exception)
+#endif
 
-asmlinkage void data_exception(struct pt_regs * regs, long error_code)
+asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 {
         __u8 opcode[6];
 	__u16 *location;
 	int do_sig = 0;
 
         lock_kernel();
-		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 	if(MACHINE_HAS_IEEE)
 	{
 		__asm__ volatile ("stfpc %0\n\t" 
@@ -374,31 +242,32 @@
 			(addr_t)ADDR_BITS_REMOVE((addr_t)location);
 		force_sig(SIGFPE, current);
 	}
+#ifdef CONFIG_IEEEFPU_EMULATION
         else if ((regs->psw.mask & 0x00010000L)) 
 	{
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
 		case 0x28: /* LDR Rx,Ry   */
-			math_emu_ldr(opcode);
+			do_sig=math_emu_ldr(opcode);
 			break;
 		case 0x38: /* LER Rx,Ry   */
-			math_emu_ler(opcode);
+			do_sig=math_emu_ler(opcode);
 			break;
 		case 0x60: /* STD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_std(opcode, regs);
+			do_sig=math_emu_std(opcode, regs);
 			break;
 		case 0x68: /* LD R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_ld(opcode, regs);
+			do_sig=math_emu_ld(opcode, regs);
 			break;
 		case 0x70: /* STE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_ste(opcode, regs);
+			do_sig=math_emu_ste(opcode, regs);
 			break;
 		case 0x78: /* LE R,D(X,B) */
 			get_user(*((__u16 *) (opcode+2)), location+1);
-			math_emu_le(opcode, regs);
+			do_sig=math_emu_le(opcode, regs);
 			break;
 		case 0xb3:
 			get_user(*((__u16 *) (opcode+2)), location+1);
@@ -427,24 +296,14 @@
 			break;
                 }
         } 
+#endif
 	else
 		do_sig = 1;
-	if (do_sig) {
-                if (check_for_fixup(regs) == 0) {
-                        current->tss.error_code = error_code;
-                        current->tss.trap_no = 7;
-                        force_sig(SIGILL, current);
-                        die("data exception", regs, error_code);
-                }
-        }
+        if (do_sig)
+                do_trap(interruption_code, SIGILL, "data exception", regs);
         unlock_kernel();
 }
 
-#else
-DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current)
-DO_ERROR(6, SIGILL, "specification exception", specification_exception, current)
-DO_ERROR(7, SIGILL, "data exception", data_exception, current)
-#endif /* CONFIG_IEEEFPU_EMULATION */
 
 
 /* init is done in lowcore.S and head.S */
@@ -487,7 +346,7 @@
 		/* I've seen this possibly a task structure being reused ? */
 		printk("Spurious per exception detected\n");
 		printk("switching off per tracing for this task.\n");
-		show_crashed_task_info();
+		show_regs(regs);
 		/* Hopefully switching off per tracing will help us survive */
 		regs->psw.mask &= ~PSW_PER_MASK;
 	}
diff -urN linux-2.2.18-pre20/arch/s390/lib/Makefile linux/arch/s390/lib/Makefile
--- linux-2.2.18-pre20/arch/s390/lib/Makefile	Tue Jan  4 10:12:12 2000
+++ linux/arch/s390/lib/Makefile	Mon Dec  3 22:14:16 2001
@@ -11,7 +11,7 @@
 endif
 
 L_TARGET = lib.a
-L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o
+L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.2.18-pre20/arch/s390/lib/delay.c linux/arch/s390/lib/delay.c
--- linux-2.2.18-pre20/arch/s390/lib/delay.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/lib/delay.c	Mon Dec  3 22:14:16 2001
@@ -27,7 +27,7 @@
          * yield the megahertz number of the cpu. The important function
          * is udelay and that is done using the tod clock. -- martin.
          */
-	__asm__ __volatile__(
+        __asm__ __volatile__(
                 "0: brct %0,0b"
                 : /* no outputs */ : "r" (loops/2) );
 }
diff -urN linux-2.2.18-pre20/arch/s390/lib/uaccess.S linux/arch/s390/lib/uaccess.S
--- linux-2.2.18-pre20/arch/s390/lib/uaccess.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/lib/uaccess.S	Mon Dec  3 22:14:16 2001
@@ -0,0 +1,51 @@
+/*
+ *  arch/s390/lib/uaccess.S
+ *    fixup routines for copy_{from|to}_user functions.
+ *
+ *  s390
+ *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  These functions have a non-standard call interface
+ */
+
+#include <asm/lowcore.h>
+
+        .text
+        .align 4
+        .globl __copy_from_user_fixup
+__copy_from_user_fixup:
+        l     1,__LC_PGM_OLD_PSW+4
+        sll   4,1
+        srl   4,1
+0:      lhi   3,-4096
+        sll   3,1
+        srl   3,1
+        n     3,__LC_TRANS_EXC_ADDR
+        sr    3,4
+        bm    4(1)
+1:      mvcle 2,4,0
+        b     4(1)
+        .section __ex_table,"a"
+	.long 1b,0b
+        .previous
+
+        .align 4
+        .text
+        .globl __copy_to_user_fixup
+__copy_to_user_fixup:
+        l     1,__LC_PGM_OLD_PSW+4
+        sll   4,1
+        srl   4,1
+0:      lhi   5,-4096
+        sll   5,1
+        srl   5,1
+        n     5,__LC_TRANS_EXC_ADDR
+        sr    5,4
+        bm    4(1)
+1:      mvcle 4,2,0
+        b     4(1)
+        .section __ex_table,"a"
+        .long 1b,0b
+        .previous
+
diff -urN linux-2.2.18-pre20/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c
--- linux-2.2.18-pre20/arch/s390/mm/fault.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/mm/fault.c	Mon Dec  3 22:14:16 2001
@@ -48,6 +48,7 @@
         int write;
         unsigned long psw_mask;
         unsigned long psw_addr;
+	int kernel_address = 0;
 
         /*
          *  get psw mask of Program old psw to find out,
@@ -71,6 +72,49 @@
         if (atomic_read(&S390_lowcore.local_irq_count))
                 die("page fault from irq handler",regs,error_code);
 
+	/*
+	 * Check which address space the address belongs to
+	 */
+	switch (S390_lowcore.trans_exc_code & 3)
+	{
+	case 0: /* Primary Segment Table Descriptor */
+		kernel_address = 1;
+		goto no_context;
+
+	case 1: /* STD determined via access register */
+		if (S390_lowcore.exc_access_id == 0)
+		{
+			kernel_address = 1;
+			goto no_context;
+		}
+		if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
+		{
+			if (regs->acrs[S390_lowcore.exc_access_id] == 0)
+			{
+				kernel_address = 1;
+				goto no_context;
+			}
+			if (regs->acrs[S390_lowcore.exc_access_id] == 1)
+			{
+				/* user space address */
+				break;
+			}
+		}
+		die("page fault via unknown access register", regs, error_code);
+		break;
+
+	case 2: /* Secondary Segment Table Descriptor */
+	case 3: /* Home Segment Table Descriptor */
+		/* user space address */
+		break;
+	}
+
+
+	/*
+	 * When we get here, the fault happened in the current
+	 * task's user address space, so we search the VMAs
+	 */
+
         down(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
@@ -129,12 +173,12 @@
         /* User mode accesses just cause a SIGSEGV */
         if (psw_mask & PSW_PROBLEM_STATE) {
                 tsk->tss.prot_addr = address;
-                tsk->tss.error_code = error_code;
-                tsk->tss.trap_no = 14;
-
+                tsk->tss.trap_no = error_code;
+#ifdef CONFIG_PROCESS_DEBUG
                 printk("User process fault: interruption code 0x%lX\n",error_code);
                 printk("failing address: %lX\n",address);
-		show_crashed_task_info();
+		show_regs(regs);
+#endif
                 force_sig(SIGSEGV, tsk);
                 return;
 	}
@@ -149,14 +193,13 @@
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
- *
- * First we check if it was the bootup rw-test, though..
  */
-        if (address < PAGE_SIZE)
-                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+        if (kernel_address)
+                printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+        	       " at virtual kernel address %08lx\n", address);
         else
-                printk(KERN_ALERT "Unable to handle kernel paging request");
-        printk(" at virtual address %08lx\n",address);
+                printk(KERN_ALERT "Unable to handle kernel paging request"
+		       " at virtual user address %08lx\n", address);
 /*
  * need to define, which information is useful here
  */
@@ -171,17 +214,17 @@
  */
 out_of_memory:
 	if (tsk->pid == 1)
-                {
+	{
 		tsk->policy |= SCHED_YIELD;
 		schedule();
 		goto survive;
-		    }
+	}
 	up(&mm->mmap_sem);
 	if (psw_mask & PSW_PROBLEM_STATE)
 	{
 		printk("VM: killing process %s\n", tsk->comm);
 		do_exit(SIGKILL);
-                }
+	}
 	goto no_context;
 
 do_sigbus:
@@ -192,8 +235,7 @@
 	 * or user mode.
 	 */
         tsk->tss.prot_addr = address;
-        tsk->tss.error_code = error_code;
-        tsk->tss.trap_no = 14;
+        tsk->tss.trap_no = error_code;
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
diff -urN linux-2.2.18-pre20/arch/s390/mm/init.c linux/arch/s390/mm/init.c
--- linux-2.2.18-pre20/arch/s390/mm/init.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/mm/init.c	Mon Dec  3 22:14:16 2001
@@ -251,6 +251,7 @@
         unsigned long tmp;
         unsigned long address=0;
         unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
+        static const int ssm_mask = 0x04000000L;
 
 	/* unmap whole virtual address space */
 
@@ -295,7 +296,9 @@
         /* enable virtual mapping in kernel mode */
         __asm__ __volatile__("    LCTL  1,1,%0\n"
                              "    LCTL  7,7,%0\n"
-                             "    LCTL  13,13,%0" : :"m" (pgdir_k));
+                             "    LCTL  13,13,%0\n"
+                             "    SSM   %1"
+                             : : "m" (pgdir_k), "m" (ssm_mask));
 
         local_flush_tlb();
 
diff -urN linux-2.2.18-pre20/arch/s390/tools/dasdfmt/dasdfmt.8 linux/arch/s390/tools/dasdfmt/dasdfmt.8
--- linux-2.2.18-pre20/arch/s390/tools/dasdfmt/dasdfmt.8	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.8	Mon Dec  3 22:14:16 2001
@@ -1,68 +1,68 @@
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
+.TH DASDFMT 8 "Tue Jan 25 2000"
+.UC 4
+.SH NAME
+dasdfmt \- formatting of DSAD (ECKD) disk drives.
+.SH SYNOPSIS
 \fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR 
-Start formatting without further user-confirmation.
-
-.TP
+.SH DESCRIPTION
+\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
+for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
+\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
+
+.SH OPTIONS
+.TP
+\fB-t\fR
+Disables any modification of the disk drive. \fBdasdfmt\fR just prints
+out, what it \fBwould\fR do.
+
+.TP
+\fB-v\fR
+Increases verbosity.
+
+.TP
+\fB-y\fR 
+Start formatting without further user-confirmation.
+
+.TP
 \fB-L\fR 
 Omit the writing of a disk label after formatting.
 
 .TP
-\fB-V\fR 
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
+\fB-V\fR 
+Print version number and exit.
+
+.TP
+\fB-b\fR \fIblockSize\fR
+Specify blocksize to be used. \fIblocksize\fR must be a positive integer
+and always be a power of two. Due due some limitations in the driver,
+it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
+
+.TP
 \fB-l\fR \fIdiskLabel\fR
 Specify the label to be written to disk after formatting. If no label is
 specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
 ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
+
+.TP
+\fIdiskSpec\fR
+This parameter specified the device to be formatted. It also can be
+given in two variants:
+.sp
 	\fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
-	\fB-n\fR \fIdevnum\fR
-.sp
-The first form uses the commonly used
-.SM UNIX
-device notation where \fIX\fR is a single lowercase letter.
+.br
+or
+.br
+	\fB-n\fR \fIdevnum\fR
+.sp
+The first form uses the commonly used
+.SM UNIX
+device notation where \fIX\fR is a single lowercase letter.
 The second form uses simply the device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
+
+.SH BUGS
+None so far ;-)
+
+.SH AUTHOR
+.nf
+This man-page was written by Fritz Elfert <felfert@to.com>
+.fi
diff -urN linux-2.2.18-pre20/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c
--- linux-2.2.18-pre20/arch/s390/tools/dasdfmt/dasdfmt.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.c	Mon Dec  3 22:14:16 2001
@@ -458,12 +458,11 @@
 void
 do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
 	int verbosity,int writenolabel,int labelspec,
-	char *label,int withoutprompt)
+	char *label,int withoutprompt,int devno)
 {
 	int fd,rc;
 	struct stat stat_buf;
 	kdev_t minor_no,major_no;
-	int devno;
 	int new_blksize;
 	unsigned int label_position;
 	struct hd_geometry new_geometry;
@@ -489,7 +488,7 @@
 		minor_no=MINOR(stat_buf.st_rdev);
 	}
 	check_mounted(major_no, minor_no);
-	
+
 	if ((!writenolabel) && (!labelspec)) {
 		sprintf(label,"LNX1 x%04x",devno);
 	}
@@ -645,9 +644,10 @@
 	endptr=NULL;
 
 	/* set default values */
-	format_params.start_unit=0;
-	format_params.stop_unit=-1;
-	format_params.blksize=4096;
+	format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
+	format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
+	format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
+	format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
 	testmode=0;
 	verbosity=0;
 	withoutprompt=0;
@@ -811,7 +811,7 @@
 
 	/******* issue the real command and reread part table *******/
 	do_format_dasd(dev_name,format_params,testmode,verbosity,
-		writenolabel,labelspec,label,withoutprompt);
+		writenolabel,labelspec,label,withoutprompt,devno);
 
 	/*************** cleanup ********************************/
 	if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
diff -urN linux-2.2.18-pre20/arch/s390/tools/hwc/Makefile linux/arch/s390/tools/hwc/Makefile
--- linux-2.2.18-pre20/arch/s390/tools/hwc/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/tools/hwc/Makefile	Mon Dec  3 22:14:16 2001
@@ -0,0 +1,12 @@
+CROSS_COMPILE = s390-
+
+hwc_measure: hwc_measure.c
+	$(CROSS_COMPILE)gcc -o $@ $^
+
+hwc_cntl_key: hwc_cntl_key.c
+	$(CROSS_COMPILE)gcc -o $@ $^
+
+clean:
+	rm -f hwc_measure
+	rm -f hwc_cntl_key
+
diff -urN linux-2.2.18-pre20/arch/s390/tools/hwc/hwc_cntl_key.c linux/arch/s390/tools/hwc/hwc_cntl_key.c
--- linux-2.2.18-pre20/arch/s390/tools/hwc/hwc_cntl_key.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/tools/hwc/hwc_cntl_key.c	Mon Dec  3 22:14:16 2001
@@ -0,0 +1,69 @@
+/*
+ * small application to set string that will be used as CNTL-C 
+ * employing a HWC terminal ioctl command
+ *
+ * returns:	number of written or read characters
+ *
+ * Copyright (C) 2000 IBM Corporation
+ * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+/* everything about the HWC terminal driver ioctl-commands */
+#include "../../../../drivers/s390/char/hwc_tty.h"
+
+/* standard input, should be our HWC tty */
+#define DESCRIPTOR 0
+
+int main(int argc, char *argv[], char *env[])
+{
+	unsigned char buf[HWC_TTY_MAX_CNTL_SIZE];
+
+	if (argc >= 2) {
+		if (strcmp(argv[1], "c") == 0 ||
+		    strcmp(argv[1], "C") == 0 ||
+		    strcmp(argv[1], "INTR_CHAR") == 0) {
+			if (argc == 2) {
+				ioctl(DESCRIPTOR, TIOCHWCTTYGINTRC, buf);
+				printf("%s\n", buf);
+				return strlen(buf);
+			} else return ioctl(DESCRIPTOR, TIOCHWCTTYSINTRC, argv[2]);
+// currently not yet implemented in HWC terminal driver
+#if 0
+		} else if (strcmp(argv[1], "d") == 0 ||
+                	   strcmp(argv[1], "D") == 0 ||
+                	   strcmp(argv[1], "EOF_CHAR") == 0) {
+	                if (argc == 2) {
+        	                ioctl(DESCRIPTOR, TIOCHWCTTYGEOFC, buf);
+                	        printf("%s\n", buf);
+                        	return strlen(buf);
+			} else return ioctl(DESCRIPTOR, TIOCHWCTTYSEOFC, argv[2]);
+	        } else if (strcmp(argv[1], "z") == 0 ||
+                	   strcmp(argv[1], "Z") == 0 ||
+                	   strcmp(argv[1], "SUSP_CHAR") == 0) {
+                	if (argc == 2) {
+                        	ioctl(DESCRIPTOR, TIOCHWCTTYGSUSPC, buf);
+                        	printf("%s\n", buf);
+                        	return strlen(buf);
+                	} else return ioctl(DESCRIPTOR, TIOCHWCTTYSSUSPC, argv[2]);
+        	} else if (strcmp(argv[1], "n") == 0 ||
+                   	   strcmp(argv[1], "N") == 0 ||
+                   	   strcmp(argv[1], "NEW_LINE") == 0) {
+                	if (argc == 2) {
+                        	ioctl(DESCRIPTOR, TIOCHWCTTYGNL, buf);
+                        	printf("%s\n", buf);
+                        	return strlen(buf);
+                	} else return ioctl(DESCRIPTOR, TIOCHWCTTYSNL, argv[2]);
+#endif
+		}
+	}
+
+	printf("usage: hwc_cntl_key <control-key> [<new string>]\n");
+	printf("  <control-key> ::= \"c\" | \"C\" | \"INTR_CHAR\" |\n");
+	printf("                    \"d\" | \"D\" | \"EOF_CHAR\" |\n");
+	printf("                    \"z\" | \"Z\" | \"SUSP_CHAR\" |\n");
+	printf("                    \"n\" | \"N\" | \"NEW_LINE\"\n");
+	return -1;
+}
diff -urN linux-2.2.18-pre20/arch/s390/tools/hwc/hwc_measure.c linux/arch/s390/tools/hwc/hwc_measure.c
--- linux-2.2.18-pre20/arch/s390/tools/hwc/hwc_measure.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/s390/tools/hwc/hwc_measure.c	Mon Dec  3 22:14:16 2001
@@ -0,0 +1,79 @@
+/*
+ * small application for HWC measurement 
+ *
+ * Copyright (C) 2000 IBM Corporation
+ * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+/* everything about the HWC low level driver ioctl-commands */
+#include "../../../../drivers/s390/char/hwc_rw.h"
+
+/* standard input, should be our HWC tty */
+#define DESCRIPTOR 0
+
+int main(int argc, char *argv[], char *env[])
+{
+	ioctl_meas_t	measured = 0;
+	signed int	retval = 0;
+
+	if (argc = 2) {
+
+		if (strcmp(argv[1], "lines") == 0) {
+			retval = ioctl(DESCRIPTOR, TIOCHWCGMEASL,
+					&measured);
+			if (retval < 0)
+				return errno;
+			else {
+				printf("%ld\n", measured);
+				return retval;
+			}
+		}
+
+		if (strcmp(argv[1], "chars") == 0) {
+			retval = ioctl(DESCRIPTOR, TIOCHWCGMEASC,
+					&measured);
+			if (retval < 0)
+				return errno;
+			else {
+				printf("%ld\n", measured);
+				return retval;
+			}
+		}
+
+		if (strcmp(argv[1], "wcalls") == 0) {
+			retval = ioctl(DESCRIPTOR, TIOCHWCGMEASS,
+					&measured);
+			if (retval < 0)
+				return errno;
+			else {
+				printf("%ld\n", measured);
+				return retval;
+			}
+		}
+
+		if (strcmp(argv[1], "reset") == 0) {
+			retval = ioctl(DESCRIPTOR, TIOCHWCSMEAS);
+			if (retval < 0)
+				return errno;
+			else	return retval;
+		}
+	}
+
+	printf("usage:\n");
+	printf("   hwc_measure lines          "
+		"(prints # of measured lines)        or\n");
+	printf("   hwc_measure_chars          "
+		"(prints # of measured characters)   or\n");
+	printf("   hwc_measure wcalls         "
+		"(prints # of measured write calls to HWC interface)   or\n");
+	printf("   hwc_measure reset          "
+		"(resets measurement counters)\n");
+
+	return -1;
+}
+
diff -urN linux-2.2.18-pre20/arch/s390/tools/hwc_cntl_key/Makefile linux/arch/s390/tools/hwc_cntl_key/Makefile
--- linux-2.2.18-pre20/arch/s390/tools/hwc_cntl_key/Makefile	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/tools/hwc_cntl_key/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-CROSS_COMPILE = s390-
-
-all: hwc_cntl_key
-
-hwc_cntl_key: hwc_cntl_key.c
-	$(CROSS_COMPILE)gcc -o $@ $^
-	$(STRIP) $@
-
-clean:
-	rm -f hwc_cntl_key.c
-
diff -urN linux-2.2.18-pre20/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c linux/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c
--- linux-2.2.18-pre20/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*
- * small application to set string that will be used as CNTL-C 
- * employing a HWC terminal ioctl command
- *
- * returns:	number of written or read characters
- *
- * Copyright (C) 2000 IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
- */
-
-#include <string.h>
-#include <stdio.h>
-
-/* everything about the HWC terminal driver ioctl-commands */
-#include "../../../../drivers/s390/char/hwc_tty.h"
-
-/* standard input, should be our HWC tty */
-#define DESCRIPTOR 0
-
-int main(int argc, char *argv[], char *env[])
-{
-	unsigned char buf[HWC_TTY_MAX_CNTL_SIZE];
-
-	if (argc >= 2) {
-		if (strcmp(argv[1], "c") == 0 ||
-		    strcmp(argv[1], "C") == 0 ||
-		    strcmp(argv[1], "INTR_CHAR") == 0) {
-			if (argc == 2) {
-				ioctl(DESCRIPTOR, TIOCHWCTTYGINTRC, buf);
-				printf("%s\n", buf);
-				return strlen(buf);
-			} else return ioctl(DESCRIPTOR, TIOCHWCTTYSINTRC, argv[2]);
-// currently not yet implemented in HWC terminal driver
-#if 0
-		} else if (strcmp(argv[1], "d") == 0 ||
-                	   strcmp(argv[1], "D") == 0 ||
-                	   strcmp(argv[1], "EOF_CHAR") == 0) {
-	                if (argc == 2) {
-        	                ioctl(DESCRIPTOR, TIOCHWCTTYGEOFC, buf);
-                	        printf("%s\n", buf);
-                        	return strlen(buf);
-			} else return ioctl(DESCRIPTOR, TIOCHWCTTYSEOFC, argv[2]);
-	        } else if (strcmp(argv[1], "z") == 0 ||
-                	   strcmp(argv[1], "Z") == 0 ||
-                	   strcmp(argv[1], "SUSP_CHAR") == 0) {
-                	if (argc == 2) {
-                        	ioctl(DESCRIPTOR, TIOCHWCTTYGSUSPC, buf);
-                        	printf("%s\n", buf);
-                        	return strlen(buf);
-                	} else return ioctl(DESCRIPTOR, TIOCHWCTTYSSUSPC, argv[2]);
-        	} else if (strcmp(argv[1], "n") == 0 ||
-                   	   strcmp(argv[1], "N") == 0 ||
-                   	   strcmp(argv[1], "NEW_LINE") == 0) {
-                	if (argc == 2) {
-                        	ioctl(DESCRIPTOR, TIOCHWCTTYGNL, buf);
-                        	printf("%s\n", buf);
-                        	return strlen(buf);
-                	} else return ioctl(DESCRIPTOR, TIOCHWCTTYSNL, argv[2]);
-#endif
-		}
-	}
-
-	printf("usage: hwc_cntl_key <control-key> [<new string>]\n");
-	printf("  <control-key> ::= \"c\" | \"C\" | \"INTR_CHAR\" |\n");
-	printf("                    \"d\" | \"D\" | \"EOF_CHAR\" |\n");
-	printf("                    \"z\" | \"Z\" | \"SUSP_CHAR\" |\n");
-	printf("                    \"n\" | \"N\" | \"NEW_LINE\"\n");
-	return -1;
-}
diff -urN linux-2.2.18-pre20/arch/s390/tools/silo/silo.c linux/arch/s390/tools/silo/silo.c
--- linux-2.2.18-pre20/arch/s390/tools/silo/silo.c	Mon Sep  4 10:39:16 2000
+++ linux/arch/s390/tools/silo/silo.c	Mon Dec  3 22:14:16 2001
@@ -144,7 +144,7 @@
 	if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) 
 		o->parmfile = tmp;
 	if ( ! o -> ramdisk ) 
-	o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
+		o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
 	tmp = cfg_get_strg(cf_options, "bootsect");
 	if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
 		o->bootsect = tmp;
@@ -181,7 +181,7 @@
 		return pfile;
 	of = fopen(pfile, "r");
 	if ( of ) {
-	NTRY( fn = tempnam(NULL,"parm."));
+		NTRY( fn = tempnam(NULL,"parm."));
 	} else {
 		fn = pfile;
 	}
@@ -193,11 +193,11 @@
 		}
 	}
 	if (root)
-		fprintf(f, "root=%s ", root);
+		fprintf(f, " root=%s", root);
 	if (ro)
-		fprintf(f, "ro ");
+		fprintf(f, " ro");
 	if (append)
-		fprintf(f, "%s", append);
+		fprintf(f, " %s", append);
 	fprintf(f, "\n");
 	fclose(f);
 	fclose(of);
@@ -312,7 +312,7 @@
   int bs = 1024;
   int l;
 
-  ITRY (stat (name, &dst));
+  ITRY(stat ( name, &dst ));
   if (S_ISREG (dst.st_mode))
     {
       if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
@@ -394,9 +394,9 @@
   PRINT_LEVEL (1, "...ok...");
   o->parmfile = gen_tmpparm(o->parmfile);
   PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
-      ITRY (verify_file (o->parmfile, dev));
-      PRINT_LEVEL (1, "...ok...");
-      PRINT_LEVEL (0, "\n");
+  ITRY (verify_file (o->parmfile, dev));
+  PRINT_LEVEL (1, "...ok...");
+  PRINT_LEVEL (0, "\n");
 
   if (o->ramdisk)
     {
@@ -492,9 +492,9 @@
       int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
       PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
 	if ( o->testlevel <= 1 ) {
-      NTRY (write (s_fd, &offset, sizeof (int)));
-      NTRY (write (s_fd, &addrct, sizeof (int)));
-    }
+	      NTRY (write (s_fd, &offset, sizeof (int)));
+	      NTRY (write (s_fd, &addrct, sizeof (int)));
+	}
     }
   ITRY (ioctl (s_fd,FIGETBSZ, &bs));
   ITRY (stat (o->bootmap, &s_st));
@@ -508,7 +508,7 @@
   NTRY ( tmpdev = tmpnam(NULL) );
   ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
   ITRY (bd_fd = open (tmpdev, O_RDONLY));
-  ITRY ( ioctl(s_fd,FIBMAP,&boots));
+  ITRY (ioctl(s_fd,FIBMAP,&boots));
   ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
   PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
   close (bd_fd);
diff -urN linux-2.2.18-pre20/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.2.18-pre20/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 22:14:07 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 22:14:16 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62.2.16 2000/09/05 00:10:54 davem Exp $
+/* $Id: ioctl32.c,v 1.62.2.17 2000/11/08 09:43:04 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -2793,6 +2793,7 @@
 	case ENVCTRL_RD_ETHERNET_TEMPERATURE:
 	case ENVCTRL_RD_MTHRBD_TEMPERATURE:
 	case ENVCTRL_RD_CPU_VOLTAGE:
+	case ENVCTRL_RD_GLOBALADDRESS:
 	case D7SIOCWR:
 	/* case D7SIOCRD: Same value as ENVCTRL_RD_VOLTAGE_STATUS */
 	case D7SIOCTM:
diff -urN linux-2.2.18-pre20/drivers/Makefile linux/drivers/Makefile
--- linux-2.2.18-pre20/drivers/Makefile	Mon Dec  3 22:14:07 2001
+++ linux/drivers/Makefile	Mon Dec  3 22:14:16 2001
@@ -43,7 +43,7 @@
 MOD_SUB_DIRS += video
 endif
 
-ifdef CONFIG_PPC
+ifdef CONFIG_POWERMAC
 SUB_DIRS += macintosh
 MOD_SUB_DIRS += macintosh
 endif
diff -urN linux-2.2.18-pre20/drivers/block/Config.in linux/drivers/block/Config.in
--- linux-2.2.18-pre20/drivers/block/Config.in	Mon Dec  3 22:14:07 2001
+++ linux/drivers/block/Config.in	Mon Dec  3 22:14:16 2001
@@ -53,7 +53,7 @@
           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
       fi
     fi
-    if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+    if [ "$CONFIG_POWERMAC" = "y" ]; then
       bool '   Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
         if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
           bool '     PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
diff -urN linux-2.2.18-pre20/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-2.2.18-pre20/drivers/block/genhd.c	Mon Dec  3 22:14:07 2001
+++ linux/drivers/block/genhd.c	Mon Dec  3 22:14:16 2001
@@ -29,6 +29,10 @@
 #include <linux/blk.h>
 #include <linux/init.h>
 
+#ifdef CONFIG_ARCH_S390
+#include <asm/dasd.h>
+#endif /* CONFIG_ARCH_S390 */
+
 #include <asm/system.h>
 #include <asm/byteorder.h>
 
@@ -67,7 +71,7 @@
 extern int net_dev_init(void);
 
 #ifdef CONFIG_PPC
-extern void note_bootable_part(kdev_t dev, int part);
+extern void note_bootable_part(kdev_t dev, int part, int goodness);
 #endif
 
 static char *raid_name (struct gendisk *hd, int minor, int major_base,
@@ -84,6 +88,10 @@
         return buf;
 }
 
+#ifdef CONFIG_ARCH_S390
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+#endif
+
 /*
  * disk_name() is used by genhd.c and md.c.
  * It formats the devicename of the indicated disk
@@ -96,6 +104,14 @@
 	const char *maj = hd->major_name;
 	int unit = (minor >> hd->minor_shift) + 'a';
 
+#ifdef CONFIG_ARCH_S390
+	if ( strncmp ( hd->major_name,"dasd",4) == 0 ){
+		part = minor & ((1 << hd->minor_shift) - 1);
+		if ( genhd_dasd_name )
+			genhd_dasd_name(buf,minor>>hd->minor_shift,part,hd);
+		return buf;
+	} 
+#endif
 	/*
 	 * IDE devices use multiple major numbers, but the drives
 	 * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
@@ -1179,7 +1195,8 @@
 				goodness++;
 
 			if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
-			    || strcasecmp(part->type, "Linux_PPC") == 0) {
+			    || (strnicmp(part->type, "Linux", 5) == 0
+			        && strcasecmp(part->type, "Linux_swap") != 0)) {
 				int i, l;
 
 				goodness++;
@@ -1208,7 +1225,7 @@
 	}
 #ifdef CONFIG_PPC
 	if (found_root_goodness)
-		note_bootable_part(dev, found_root);
+		note_bootable_part(dev, found_root, found_root_goodness);
 #endif
 	brelse(bh);
 	printk("\n");
@@ -1402,10 +1419,11 @@
 #endif /* CONFIG_ULTRIX_PARTITION */
 
 #ifdef CONFIG_ARCH_S390
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+#include <linux/ioctl.h>
 #include <asm/ebcdic.h>
-#include "../s390/block/dasd_types.h"
-
-dasd_information_t **dasd_information = NULL;
+#include <asm/uaccess.h>
 
 typedef enum {
   ibm_partition_none = 0,
@@ -1442,14 +1460,45 @@
 	ibm_partition_t partition_type;
 	char type[5] = {0,};
 	char name[7] = {0,};
-        int di = MINOR(dev) >> hd->minor_shift;
-        if ( ! get_ptable_blocksize(dev) )
+	struct hd_geometry geo;
+	mm_segment_t old_fs;
+	int blocksize;
+	struct file *filp = NULL;
+	struct inode *inode = NULL;
+	int offset, size;
+	int rc;
+
+	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
+	if ( blocksize <= 0 ) {
 		return 0;
-	if ( ! dasd_information )
+	}
+	set_blocksize(dev, blocksize);  /* OUCH !! */
+
+	/* find out offset of volume label (partn table) */
+	filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+	if ( filp == NULL ) {
+		printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed for filp\n");
+		return 0;
+	}
+	memset(filp,0,sizeof(struct file));
+	filp ->f_mode = 1; /* read only */
+	inode = get_empty_inode();
+	inode -> i_rdev = dev;
+	rc = blkdev_open(inode,filp);
+	if ( rc ) {
+		return 0;
+	}
+	old_fs=get_fs();
+	set_fs(KERNEL_DS);
+	rc = filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
+	set_fs(old_fs);
+	if ( rc ) {
 		return 0;
-	if ( ( bh = bread( dev, 
-			 dasd_information[di]->sizes.label_block, 
-			 dasd_information[di]->sizes.bp_sector ) ) != NULL ) {
+	}
+	blkdev_release(inode);
+	
+	size = hd -> sizes[MINOR(dev)]<<1;
+	if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
 		strncpy ( type,bh -> b_data, 4);
 		strncpy ( name,bh -> b_data + 4, 6);
         } else {
@@ -1459,50 +1508,45 @@
 		EBCASC(name,6);
 	}
 	switch ( partition_type = get_partition_type(type) ) {
-	case ibm_partition_lnx1:
+	case ibm_partition_lnx1: 
+		offset = (geo.start + 1);
 		printk ( "(LNX1)/%6s:",name);
-		add_partition( hd, MINOR(dev) + 1, 
-				  (dasd_information[di]->sizes.label_block + 1) <<
-				   dasd_information[di]->sizes.s2b_shift,
-				  (dasd_information [di]->sizes.blocks -
-				    dasd_information[di]->sizes.label_block - 1) <<
-				  dasd_information[di]->sizes.s2b_shift,0 );
 		break;
 	case ibm_partition_vol1:
+		offset = 0;
+		size = 0;
 		printk ( "(VOL1)/%6s:",name);
 		break;
 	case ibm_partition_cms1:
 		printk ( "(CMS1)/%6s:",name);
 		if (* (((long *)bh->b_data) + 13) == 0) {
 			/* disk holds a CMS filesystem */
-			add_partition( hd, MINOR(dev) + 1, 
-				       (dasd_information [di]->sizes.label_block + 1) <<
-				       dasd_information [di]->sizes.s2b_shift,
-				       (dasd_information [di]->sizes.blocks -
-					dasd_information [di]->sizes.label_block) <<
-				       dasd_information [di]->sizes.s2b_shift,0 );
+			offset = (geo.start + 1);
 			printk ("(CMS)");
 		} else {
-		  /* disk is reserved minidisk */
-                        long *label=(long*)bh->b_data;
-			int offset = label[13];
-			int size = (label[7]-1-label[13])*(label[3]>>9);
-			add_partition( hd, MINOR(dev) + 1, 
-				       offset << dasd_information [di]->sizes.s2b_shift,
-				       size<<dasd_information [di]->sizes.s2b_shift,0 );
+			/* disk is reserved minidisk */
+			// mdisk_setup_data.size[i] =
+			// (label[7] - 1 - label[13]) *
+			// (label[3] >> 9) >> 1;
+			long *label=(long*)bh->b_data;
+			blocksize = label[3];
+			offset = label[13];
+			size = (label[7]-1)*(blocksize>>9); 
 			printk ("(MDSK)");
 		}
 		break;
 	case ibm_partition_none:
 		printk ( "(nonl)/      :");
-		add_partition( hd, MINOR(dev) + 1, 
-				  (dasd_information [di]->sizes.label_block + 1) <<
-				  dasd_information [di]->sizes.s2b_shift,
-				  (dasd_information [di]->sizes.blocks -
-				   dasd_information [di]->sizes.label_block - 1) <<
-				  dasd_information [di]->sizes.s2b_shift,0 );
+		offset = (geo.start+1);
 		break;
-	}
+	default:
+		offset = 0;
+		size = 0;
+		
+	}
+	add_partition( hd, MINOR(dev), 0,size,0);
+	add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
+		       size-offset*(blocksize>>9) ,0 );
 	printk ( "\n" );
 	bforget(bh);
 	return 1;
@@ -1609,14 +1653,18 @@
 		dev->part[i].start_sect = 0;
 		dev->part[i].nr_sects = 0;
 	}
-	dev->init(dev);	
+	if ( dev->init != NULL )
+		dev->init(dev);	
 	for (drive = 0 ; drive < dev->nr_real ; drive++) {
 		int first_minor	= drive << dev->minor_shift;
 		current_minor = 1 + first_minor;
-		check_partition(dev, MKDEV(dev->major, first_minor));
+		/* If we really have a device check partition table */
+		if ( blksize_size[dev->major] == NULL ||
+		     blksize_size[dev->major][current_minor])
+			check_partition(dev, MKDEV(dev->major, first_minor));
 	}
 	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
-		for (i = 0; i < end_minor; i++)
+		for (i = 0; i < end_minor; i++) 
 			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
 		blk_size[dev->major] = dev->sizes;
 	}
diff -urN linux-2.2.18-pre20/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- linux-2.2.18-pre20/drivers/block/ide-pmac.c	Mon Sep  4 10:39:16 2000
+++ linux/drivers/block/ide-pmac.c	Mon Dec  3 22:14:16 2001
@@ -23,6 +23,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/cdrom.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
@@ -93,14 +94,14 @@
 
 /* allow up to 256 DBDMA commands per xfer */
 #define MAX_DCMDS	256
-/* Wait 1.5s for disk to answer on IDE bus after
+/* Wait 2s for disk to answer on IDE bus after
  * enable operation.
  * NOTE: There is at least one case I know of a disk that needs about 10sec
  *       before anwering on the bus. I beleive we could add a kernel command
  *       line arg to override this delay for such cases.
  */
-#define IDE_WAKEUP_DELAY_MS	1500
-#define MAX_DCMDS	256	/* allow up to 256 DBDMA commands per xfer */
+#define IDE_WAKEUP_DELAY_MS	2000
+#define MAX_DCMDS		256	/* allow up to 256 DBDMA commands per xfer */
 
 static void pmac_ide_setup_dma(struct device_node *np, int ix);
 static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
@@ -393,6 +394,7 @@
 			 */
 			 feature_set(np, FEATURE_IDE0_enable);
 			 feature_set(np, FEATURE_IOBUS_enable);
+			 big_delay = 1; /* Poor old machines with crappy disks */
 		} else {
 			/* This is necessary to enable IDE when net-booting */
 			printk("pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id);
@@ -596,13 +598,13 @@
 static __inline__ int
 wait_for_ready(ide_drive_t *drive)
 {
-	/* Timeout bumped for some powerbooks */
-	int timeout = 2000;
+	/* Timeout bumped (again) for some powerbooks with old disks */
+	int timeout = 10000;
 	byte stat;
 
 	while(--timeout) {
 		stat = GET_STAT();
-		if(!(stat & BUSY_STAT)) {
+		if (!(stat & BUSY_STAT)) {
 			if (drive->ready_stat == 0)
 				break;
 			else if((stat & drive->ready_stat) || (stat & ERR_STAT))
@@ -631,20 +633,31 @@
 	old_select = IN_BYTE(IDE_SELECT_REG);
 	OUT_BYTE(drive->select.all, IDE_SELECT_REG);
 	udelay(10);
-	OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
-	OUT_BYTE(command, IDE_NSECTOR_REG);
 	if(wait_for_ready(drive)) {
 		printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
 		goto out;
 	}
+	OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
+#if 0
+	/* That one cause the wallstreet to freeze, I don't know why yet. We'll have to leave with
+         * the bogus interrupt until I figure out what's up
+         */
+	/* Better not leave a dangling interrupt */
+	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);
+#endif	
+	OUT_BYTE(command, IDE_NSECTOR_REG);
 	OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);
+	udelay(10);
 	result = wait_for_ready(drive);
 	if (result)
 		printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
+	/* May help kill the bogus interrupt */
+	mdelay(1);
+	(void)GET_STAT();
 out:
 	OUT_BYTE(old_select, IDE_SELECT_REG);
 	restore_flags(flags);
-	
+
 	return result;
 }
 
@@ -848,13 +861,15 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
 #ifdef CONFIG_PMAC_PBOOK
-static void idepmac_sleep_disk(int i, unsigned long base)
+static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
 {
-	struct device_node* np = pmac_ide[i].node;
 	int j;
-
-	/* FIXME: We only handle the master IDE */
-	if (ide_hwifs[i].drives[0].media == ide_disk) {
+	
+	/* FIXME: We only handle the master IDE disk, we shoud
+	 *        try to fix CD-ROMs here
+	 */
+	switch (drive->media) {
+	case ide_disk:
 		/* Spin down the drive */
 		outb(0xa0, base+0x60);
 		outb(0x0, base+0x30);
@@ -870,99 +885,127 @@
 			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
 				break;
 		}
-	}
-	feature_set(np, FEATURE_IDE0_reset);
-	feature_clear(np, FEATURE_IDE0_enable);
-	switch(pmac_ide[i].aapl_bus_id) {
-	    case 0:
-		feature_set(np, FEATURE_IDE0_reset);
-		feature_clear(np, FEATURE_IDE0_enable);
 		break;
-	    case 1:
-		feature_set(np, FEATURE_IDE1_reset);
-		feature_clear(np, FEATURE_IDE1_enable);
+	case ide_cdrom:
+		// todo
 		break;
-	    case 2:
-		feature_set(np, FEATURE_IDE2_reset);
+	case ide_floppy:
+		// todo
 		break;
 	}
-	pmac_ide[i].timings[0] = 0;
-	pmac_ide[i].timings[1] = 0;
 }
 
-static void idepmac_wake_disk(int i, unsigned long base)
+static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
+ {
+	unsigned long flags;
+
+	/* We force the IDE subdriver to check for a media change
+	 * This must be done first or we may lost the condition
+	 *
+	 * Problem: This can schedule. I moved the block device
+	 * wakeup almost late by priority because of that.
+	 */
+	DRIVER(drive)->media_change(drive);
+
+	/* We kick the VFS too (see fix in ide.c revalidate) */
+	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* We re-enable DMA on the drive if it was active. */
+	/* This doesn't work with the CD-ROM in the media-bay, probably
+	 * because of a pending unit attention. The problem if that if I
+	 * clear the error, the filesystem dies.
+	 */
+	if (used_dma && !ide_spin_wait_hwgroup(drive, &flags)) {
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		pmac_ide_dma_onoff(drive, 1);
+		HWGROUP(drive)->busy = 0;
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void idepmac_sleep_interface(int i, unsigned base, int mediabay)
 {
 	struct device_node* np = pmac_ide[i].node;
-	int j;
 
-	/* Revive IDE disk and controller */
+	/* We clear the timings */
+	pmac_ide[i].timings[0] = 0;
+	pmac_ide[i].timings[1] = 0;
+	
+	/* The media bay will handle itself just fine */
+	if (mediabay)
+		return;
+	
+	/* Disable and reset the bus */
+	feature_set(np, FEATURE_IDE0_reset);
+	feature_clear(np, FEATURE_IDE0_enable);
 	switch(pmac_ide[i].aapl_bus_id) {
 	    case 0:
 		feature_set(np, FEATURE_IDE0_reset);
-		feature_set(np, FEATURE_IOBUS_enable);
-		mdelay(10);
- 		feature_set(np, FEATURE_IDE0_enable);
-		mdelay(10);
-		feature_clear(np, FEATURE_IDE0_reset);
+		feature_clear(np, FEATURE_IDE0_enable);
 		break;
 	    case 1:
 		feature_set(np, FEATURE_IDE1_reset);
-		feature_set(np, FEATURE_IOBUS_enable);
-		mdelay(10);
- 		feature_set(np, FEATURE_IDE1_enable);
-		mdelay(10);
-		feature_clear(np, FEATURE_IDE1_reset);
+		feature_clear(np, FEATURE_IDE1_enable);
 		break;
 	    case 2:
-	    	/* This one exists only for KL, I don't know
-		   about any enable bit */
 		feature_set(np, FEATURE_IDE2_reset);
-		mdelay(10);
-		feature_clear(np, FEATURE_IDE2_reset);
 		break;
 	}
-	mdelay(IDE_WAKEUP_DELAY_MS);
-
-	/* Reset timings */
-	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
-	mdelay(10);
-
-	/* Wait up to 10 seconds (enough for recent drives) */
-	for (j = 0; j < 100; j++) {
-		int status;
-		mdelay(100);
-		status = inb(base + 0x70);
-		if (!(status & BUSY_STAT))
-			break;
-	}
 }
 
-/* Here we handle media bay devices */
-static void
-idepmac_wake_bay(int i, unsigned long base)
+static void idepmac_wake_interface(int i, unsigned long base, int mediabay)
 {
-	int timeout;
+	struct device_node* np = pmac_ide[i].node;
 
+	if (!mediabay) {
+		/* Revive IDE disk and controller */
+		switch(pmac_ide[i].aapl_bus_id) {
+		    case 0:
+			feature_set(np, FEATURE_IDE0_reset);
+			feature_set(np, FEATURE_IOBUS_enable);
+			mdelay(10);
+	 		feature_set(np, FEATURE_IDE0_enable);
+			mdelay(10);
+			feature_clear(np, FEATURE_IDE0_reset);
+			break;
+		    case 1:
+			feature_set(np, FEATURE_IDE1_reset);
+			feature_set(np, FEATURE_IOBUS_enable);
+			mdelay(10);
+	 		feature_set(np, FEATURE_IDE1_enable);
+			mdelay(10);
+			feature_clear(np, FEATURE_IDE1_reset);
+			break;
+		    case 2:
+		    	/* This one exists only for KL, I don't know
+			   about any enable bit */
+			feature_set(np, FEATURE_IDE2_reset);
+			mdelay(10);
+			feature_clear(np, FEATURE_IDE2_reset);
+			break;
+		}
+	}
+	
 	/* Reset timings */
 	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
 	mdelay(10);
-
-	timeout = 10000;
-	while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
-		mdelay(1);
-		--timeout;
-	}
 }
 
 /* Note: We support only master drives for now. This will have to be
  * improved if we want to handle sleep on the iMacDV where the CD-ROM
  * is a slave
  */
+
 static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
 	int i, ret;
 	unsigned long base;
-
+	unsigned long flags;
+	int big_delay;
+	
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 		break;
@@ -970,37 +1013,108 @@
 		break;
 	case PBOOK_SLEEP_NOW:
 		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			ide_drive_t *drive;
+			int unlock = 0;
+
 			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
+				continue;	
+
+			hwif = &ide_hwifs[i];
+			drive = &hwif->drives[0];
+			
+			if (drive->present) {
+				/* Wait for HW group to complete operations */
+				if (ide_spin_wait_hwgroup(drive, &flags)) {
+					// What can we do here ? Wake drive we had already
+					// put to sleep and return an error ?
+				} else {
+					unlock = 1;
+					/* Lock HW group */
+					HWGROUP(drive)->busy = 1;
+
+					/* Stop the device */
+					idepmac_sleep_device(drive, i, base);
+				
+				}
+			}
 			/* Disable irq during sleep */
-			disable_irq(pmac_ide[i].irq);
+			disable_irq(pmac_ide[i].irq);			
+			if (unlock)
+				spin_unlock_irqrestore(&io_request_lock, flags);
+			
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay.
+			 */
 			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
-				/* not media bay - put the disk to sleep */
-				idepmac_sleep_disk(i, base);
+			if ((ret == 0) || (ret == -ENODEV))
+				idepmac_sleep_interface(i, base, (ret == 0));
 		}
 		break;
 	case PBOOK_WAKE:
+		big_delay = 0;
+		for (i = 0; i < pmac_ide_count; ++i) {
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV)) {
+				idepmac_wake_interface(i, base, (ret == 0));				
+				big_delay = 1;
+			}
+
+		}
+		/* Let hardware get up to speed */
+		if (big_delay)
+			mdelay(IDE_WAKEUP_DELAY_MS);
+	
 		for (i = 0; i < pmac_ide_count; ++i) {
 			ide_hwif_t *hwif;
+			ide_drive_t *drive;			
+			int j, used_dma;
+			
 			if ((base = pmac_ide[i].regbase) == 0)
 				continue;
+				
 			hwif = &ide_hwifs[i];
-		        /* We don't handle media bay devices this way */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
-				idepmac_wake_disk(i, base);
-			else if (ret == 0)
-				idepmac_wake_bay(i, base);
-			enable_irq(pmac_ide[i].irq);
+			drive = &hwif->drives[0];
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-			if (hwif->drives[0].present && hwif->drives[0].using_dma)
-				pmac_ide_dma_onoff(&hwif->drives[0], 1);
-#endif				
+			/* Wait for the drive to come up and set it's DMA */
+			if (drive->present) {
+				/* Wait up to 20 seconds */
+				for (j = 0; j < 200; j++) {
+					int status;
+					mdelay(100);
+					status = inb(base + 0x70);
+					if (!(status & BUSY_STAT))
+						break;
+				}
+			}
+			
+			/* We don't have re-configured DMA yet */
+			used_dma = drive->using_dma;
+			drive->using_dma = 0;
+
+			/* We resume processing on the HW group */
+			spin_lock_irqsave(&io_request_lock, flags);
+			enable_irq(pmac_ide[i].irq);
+			if (drive->present)
+				HWGROUP(drive)->busy = 0;
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			
+			/* Wake the device
+			 * We could handle the slave here
+			 */
+			if (drive->present)
+				idepmac_wake_device(drive, used_dma);
 		}
 		break;
 	}
 	return PBOOK_SLEEP_OK;
 }
+
 #endif /* CONFIG_PMAC_PBOOK */
diff -urN linux-2.2.18-pre20/drivers/block/rd.c linux/drivers/block/rd.c
--- linux-2.2.18-pre20/drivers/block/rd.c	Mon Dec  3 22:14:07 2001
+++ linux/drivers/block/rd.c	Mon Dec  3 22:14:16 2001
@@ -614,8 +614,10 @@
 #ifdef CONFIG_MAC_FLOPPY
 		if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR)
 			swim3_fd_eject(MINOR(ROOT_DEV));
+#ifdef CONFIG_BLK_DEV_INITRD
 		else if(MAJOR(real_root_dev) == FLOPPY_MAJOR)
 			swim3_fd_eject(MINOR(real_root_dev));
+#endif
 #endif
 		printk(KERN_NOTICE
 		       "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n");
diff -urN linux-2.2.18-pre20/drivers/char/Config.in linux/drivers/char/Config.in
--- linux-2.2.18-pre20/drivers/char/Config.in	Mon Dec  3 22:14:07 2001
+++ linux/drivers/char/Config.in	Mon Dec  3 22:14:16 2001
@@ -189,7 +189,7 @@
     fi
   fi
   dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
-  if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+  if [ "$CONFIG_POWERMAC" = "y" ]; then
     dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
   fi
   dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
diff -urN linux-2.2.18-pre20/drivers/char/buz.c linux/drivers/char/buz.c
--- linux-2.2.18-pre20/drivers/char/buz.c	Mon Dec  3 22:14:07 2001
+++ linux/drivers/char/buz.c	Mon Dec  3 22:14:16 2001
@@ -2390,7 +2390,7 @@
 	case VIDIOCSCHAN:
 		{
 			struct video_channel v;
-			int input;
+			int input, norm;
 			int on, res;
 
 			if (copy_from_user(&v, arg, sizeof(v))) {
@@ -2422,9 +2422,10 @@
 			if (on)
 				zr36057_overlay(zr, 0);
 
+			norm = zr->params.norm;
 			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm);
 
 			if (on)
 				zr36057_overlay(zr, 1);
@@ -2782,7 +2783,7 @@
 	case BUZIOC_S_PARAMS:
 		{
 			struct zoran_params bp;
-			int input, on;
+			int input, on, norm;
 
 			if (zr->codec_mode != BUZ_MODE_IDLE) {
 				return -EINVAL;
@@ -2809,9 +2810,10 @@
 				zr36057_overlay(zr, 0);
 
 			input = zr->params.input == 0 ? 3 : 7;
+			norm = zr->params.norm;
 			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm);
 
 			if (on)
 				zr36057_overlay(zr, 1);
@@ -2940,8 +2942,9 @@
 
 			/* restore previous input and norm */
 			input = zr->params.input == 0 ? 3 : 7;
+			norm = zr->params.norm;
 			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
-			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
 
 			if (copy_to_user(arg, &bs, sizeof(bs))) {
 				return -EFAULT;
@@ -3253,8 +3256,9 @@
 
 	j = zr->params.input == 0 ? 3 : 7;
 	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j);
-	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
-	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+	j = zr->params.norm;
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &j);
+	i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &j);
 
 	/* set individual interrupt enables (without GIRQ0)
 	   but don't global enable until zoran_open() */
diff -urN linux-2.2.18-pre20/drivers/char/console.c linux/drivers/char/console.c
--- linux-2.2.18-pre20/drivers/char/console.c	Mon Sep  4 10:39:17 2000
+++ linux/drivers/char/console.c	Mon Dec  3 22:14:16 2001
@@ -575,10 +575,12 @@
 	}
 
 	if (redraw) {
+		int update;
+		
 		set_origin(currcons);
+		update = sw->con_switch(vc_cons[currcons].d);
 		set_palette(currcons);
-		if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS)
-			/* Update the screen contents */
+		if (update && vcmode != KD_GRAPHICS)
 			do_update_region(currcons, origin, screenbuf_size/2);
 	}
 	set_cursor(currcons);
diff -urN linux-2.2.18-pre20/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- linux-2.2.18-pre20/drivers/char/keyboard.c	Mon Dec  3 22:14:08 2001
+++ linux/drivers/char/keyboard.c	Mon Dec  3 22:14:16 2001
@@ -315,7 +315,7 @@
 #if 1			/* how? two almost equivalent choices follow */
 			compute_shiftstate();
 #else
-			keysym = U(plain_map[keycode]);
+			keysym = U(key_maps[0][keycode]);
 			type = KTYP(keysym);
 			if (type == KT_SHIFT)
 			  (*key_handler[type])(keysym & 0xff, up_flag);
@@ -759,7 +759,7 @@
 	    k = i*BITS_PER_LONG;
 	    for(j=0; j<BITS_PER_LONG; j++,k++)
 	      if(test_bit(k, key_down)) {
-		sym = U(plain_map[k]);
+		sym = U(key_maps[0][k]);
 		if(KTYP(sym) == KT_SHIFT) {
 		  val = KVAL(sym);
 		  if (val == KVAL(K_CAPSSHIFT))
diff -urN linux-2.2.18-pre20/drivers/char/mem.c linux/drivers/char/mem.c
--- linux-2.2.18-pre20/drivers/char/mem.c	Mon Dec  3 22:14:08 2001
+++ linux/drivers/char/mem.c	Mon Dec  3 22:14:16 2001
@@ -52,12 +52,6 @@
 #ifdef CONFIG_MDA_CONSOLE
 extern void mda_console_init(void);
 #endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
-extern void adbdev_init(void);
-#endif
-#ifdef CONFIG_USB
-int usb_init(void);
-#endif
      
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
@@ -614,9 +608,6 @@
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 	rand_initialize();
-#ifdef CONFIG_USB
-	usb_init();
-#endif
 #if defined (CONFIG_FB)
 	fbmem_init();
 #endif
@@ -664,9 +655,6 @@
 #endif
 #ifdef CONFIG_VIDEO_BT848
 	i2c_init();
-#endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
-	adbdev_init();
 #endif
 #ifdef CONFIG_VIDEO_DEV
 	videodev_init();
diff -urN linux-2.2.18-pre20/drivers/char/misc.c linux/drivers/char/misc.c
--- linux-2.2.18-pre20/drivers/char/misc.c	Mon Dec  3 22:14:08 2001
+++ linux/drivers/char/misc.c	Mon Dec  3 22:14:16 2001
@@ -248,7 +248,7 @@
 #ifdef CONFIG_BVME6000
 	rtc_DP8570A_init();
 #endif
-#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
+#if defined(CONFIG_RTC) || defined(CONFIG_PPC_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
 	rtc_init();
 #endif
 #ifdef CONFIG_ATARI_DSP56K
diff -urN linux-2.2.18-pre20/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.2.18-pre20/drivers/char/tty_io.c	Mon Sep  4 10:39:18 2000
+++ linux/drivers/char/tty_io.c	Mon Dec  3 22:14:16 2001
@@ -129,6 +129,9 @@
 extern long console_8xx_init(long, long);
 extern int rs_8xx_init(void);
 #endif /* CONFIG_8xx */
+#ifdef CONFIG_MAC_SERIAL
+extern long mac_scc_console_init(long, long);
+#endif
 #ifdef CONFIG_3215
 extern long con3215_init(long, long);
 #endif /* CONFIG_3215 */
@@ -2097,6 +2100,8 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #ifdef CONFIG_8xx
 	kmem_start = console_8xx_init(kmem_start, kmem_end);
+#elif defined(CONFIG_MAC_SERIAL)
+	kmem_start = mac_scc_console_init(kmem_start, kmem_end);
 #else 	
 	kmem_start = serial_console_init(kmem_start, kmem_end);
 #endif /* CONFIG_8xx */
diff -urN linux-2.2.18-pre20/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- linux-2.2.18-pre20/drivers/macintosh/Makefile	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/Makefile	Mon Dec  3 22:14:16 2001
@@ -12,16 +12,16 @@
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
 
-L_TARGET := macintosh.a
+O_TARGET := macintosh.o
 M_OBJS   :=
 
 ifndef CONFIG_MBX
-L_OBJS   := via-cuda.o macio-adb.o via-pmu.o mediabay.o
-LX_OBJS  := adb.o
+O_OBJS   := via-cuda.o macio-adb.o via-pmu.o mediabay.o
+OX_OBJS  := adb.o
 endif
 
 ifeq ($(CONFIG_MAC_SERIAL),y)
-  L_OBJS += macserial.o
+  O_OBJS += macserial.o
 else
   ifeq ($(CONFIG_MAC_SERIAL),m)
     M_OBJS += macserial.o
@@ -29,7 +29,7 @@
 endif
 
 ifeq ($(CONFIG_NVRAM),y)
-  L_OBJS += nvram.o
+  O_OBJS += nvram.o
 else
   ifeq ($(CONFIG_NVRAM),m)
     M_OBJS += nvram.o
@@ -37,7 +37,7 @@
 endif
 
 ifeq ($(CONFIG_PPC_RTC),y)
-  L_OBJS += rtc.o
+  O_OBJS += rtc.o
 else
   ifeq ($(CONFIG_PPC_RTC),m)
     M_OBJS += rtc.o
@@ -45,7 +45,13 @@
 endif
 
 ifdef CONFIG_MAC_KEYBOARD
-L_OBJS += mac_keyb.o
+  O_OBJS += mac_keyb.o
+endif
+ifdef CONFIG_INPUT_ADBHID
+  O_OBJS += adbhid.o
+endif
+ifdef CONFIG_MAC_HID
+  O_OBJS += mac_hid.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.18-pre20/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- linux-2.2.18-pre20/drivers/macintosh/adb.c	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/adb.c	Mon Dec  3 22:14:16 2001
@@ -25,13 +25,13 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/notifier.h>
+#include <linux/init.h>
 #include <asm/prom.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
 #include <asm/uaccess.h>
 #include <asm/hydra.h>
-#include <asm/init.h>
 
 EXPORT_SYMBOL(adb_controller);
 EXPORT_SYMBOL(adb_client_list);
@@ -390,7 +390,7 @@
 
 #define ADB_MAJOR	56	/* major number for /dev/adb */
 
-extern void adbdev_init(void);
+extern int adbdev_init(void);
 
 struct adbdev_state {
 	spinlock_t	lock;
@@ -601,10 +601,19 @@
 	adb_release
 };
 
-void adbdev_init()
+static int __init adbdev_init(void)
 {
-	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;		
+	if (adb_controller == NULL)
+		return 0;
 	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
 		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+	return 0;
 }
+
+static void adbdev_cleanup(void)
+{
+	unregister_chrdev(ADB_MAJOR, "adb");
+}
+
+module_init(adbdev_init);
+module_exit(adbdev_cleanup);
diff -urN linux-2.2.18-pre20/drivers/macintosh/adbhid.c linux/drivers/macintosh/adbhid.c
--- linux-2.2.18-pre20/drivers/macintosh/adbhid.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/adbhid.c	Mon Dec  3 22:14:16 2001
@@ -0,0 +1,875 @@
+/*
+ * drivers/input/adbhid.c
+ *
+ * ADB HID driver for Power Macintosh computers.
+ *
+ * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 2000 Franz Sirl.
+ *
+ * Adapted to ADB changes and support for more devices by
+ * Benjamin Herrenschmidt. Adapted from code in MkLinux
+ * and reworked.
+ * 
+ * Supported devices:
+ *
+ * - Standard 1 button mouse
+ * - All standard Apple Extended protocol (handler ID 4)
+ * - mouseman and trackman mice & trackballs 
+ * - PowerBook Trackpad (default setup: enable tapping)
+ * - MicroSpeed mouse & trackball (needs testing)
+ * - CH Products Trackball Pro (needs testing)
+ * - Contour Design (Contour Mouse)
+ * - Hunter digital (NoHandsMouse)
+ * - Kensignton TurboMouse 5 (needs testing)
+ * - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
+ * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
+ *
+ * To do:
+ *
+ * Improve Kensington support.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/input.h>
+#include <linux/kbd_ll.h>
+
+#include <asm/adb.h>
+#include <asm/cuda.h>
+#include <asm/pmu.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
+
+#define KEYB_KEYREG	0	/* register # for key up/down data */
+#define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
+
+static int adb_message_handler(struct notifier_block *, unsigned long, void *);
+static struct notifier_block adbhid_adb_notifier = {
+	notifier_call:	adb_message_handler,
+};
+
+unsigned char adb_to_linux_keycodes[128] = {
+	 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19,
+	 21, 20,  2,  3,  4,  5,  7,  6, 13, 10,  8, 12,  9, 11, 27, 24,
+	 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52,
+	 15, 57, 41, 14, 96,  1, 29,125, 42, 58, 56,105,106,108,103,  0,
+	  0, 83,  0, 55,  0, 78,  0, 69,  0,  0,  0, 98, 96,  0, 74,  0,
+	  0,117, 82, 79, 80, 81, 75, 76, 77, 71,  0, 72, 73,183,181,124,
+	 63, 64, 65, 61, 66, 67,191, 87,190, 99,  0, 70,  0, 68,101, 88,
+	  0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116
+};
+
+struct adbhid {
+	struct input_dev input;
+	int id;
+	int default_id;
+	int original_handler_id;
+	int current_handler_id;
+	int mouse_kind;
+	unsigned char *keycode;
+	char name[64];
+};
+
+static struct adbhid *adbhid[16] = { 0 };
+
+static void adbhid_probe(void);
+
+static void adbhid_input_keycode(int, int, int);
+static void leds_done(struct adb_request *);
+
+static void init_trackpad(int id);
+static void init_trackball(int id);
+static void init_turbomouse(int id);
+static void init_microspeed(int id);
+static void init_ms_a3(int id);
+
+static struct adb_ids keyboard_ids;
+static struct adb_ids mouse_ids;
+static struct adb_ids buttons_ids;
+
+/* Kind of keyboard, see Apple technote 1152  */
+#define ADB_KEYBOARD_UNKNOWN	0
+#define ADB_KEYBOARD_ANSI	0x0100
+#define ADB_KEYBOARD_ISO	0x0200
+#define ADB_KEYBOARD_JIS	0x0300
+
+/* Kind of mouse  */
+#define ADBMOUSE_STANDARD_100	0	/* Standard 100cpi mouse (handler 1) */
+#define ADBMOUSE_STANDARD_200	1	/* Standard 200cpi mouse (handler 2) */
+#define ADBMOUSE_EXTENDED	2	/* Apple Extended mouse (handler 4) */
+#define ADBMOUSE_TRACKBALL	3	/* TrackBall (handler 4) */
+#define ADBMOUSE_TRACKPAD       4	/* Apple's PowerBook trackpad (handler 4) */
+#define ADBMOUSE_TURBOMOUSE5    5	/* Turbomouse 5 (previously req. mousehack) */
+#define ADBMOUSE_MICROSPEED	6	/* Microspeed mouse (&trackball ?), MacPoint */
+#define ADBMOUSE_TRACKBALLPRO	7	/* Trackball Pro (special buttons) */
+#define ADBMOUSE_MS_A3		8	/* Mouse systems A3 trackball (handler 3) */
+#define ADBMOUSE_MACALLY2	9	/* MacAlly 2-button mouse */
+
+static void
+adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
+{
+	int id = (data[0] >> 4) & 0x0f;
+
+	if (!adbhid[id]) {
+		printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n",
+		       id, data[0], data[1], data[2], data[3]);
+		return;
+	}
+
+	/* first check this is from register 0 */
+	if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
+		return;		/* ignore it */
+	kbd_pt_regs = regs;
+	adbhid_input_keycode(id, data[1], 0);
+	if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
+		adbhid_input_keycode(id, data[2], 0);
+}
+
+static void
+adbhid_input_keycode(int id, int keycode, int repeat)
+{
+	int up_flag;
+
+	up_flag = (keycode & 0x80);
+	keycode &= 0x7f;
+
+	switch (keycode) {
+	case 0x39: /* Generate down/up events for CapsLock everytime. */
+		input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1);
+		input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0);
+		return;
+	case 0x3f: /* ignore Powerbook Fn key */
+		return;
+	}
+
+	if (adbhid[id]->keycode[keycode])
+		input_report_key(&adbhid[id]->input,
+				 adbhid[id]->keycode[keycode], !up_flag);
+	else
+		printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
+		       up_flag ? "released" : "pressed");
+}
+
+static void
+adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
+	int id = (data[0] >> 4) & 0x0f;
+
+	if (!adbhid[id]) {
+		printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id);
+		return;
+	}
+
+  /*
+    Handler 1 -- 100cpi original Apple mouse protocol.
+    Handler 2 -- 200cpi original Apple mouse protocol.
+
+    For Apple's standard one-button mouse protocol the data array will
+    contain the following values:
+
+                BITS    COMMENTS
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx First button and x-axis motion.
+    data[2] = byyy yyyy Second button and y-axis motion.
+
+    Handler 4 -- Apple Extended mouse protocol.
+
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+		BITS    COMMENTS
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx Left button and x-axis motion.
+    data[2] = byyy yyyy Second button and y-axis motion.
+    data[3] = byyy bxxx Third button and fourth button.  Y is additional
+	      high bits of y-axis motion.  XY is additional
+	      high bits of x-axis motion.
+
+    MacAlly 2-button mouse protocol.
+
+    For MacAlly 2-button mouse protocol the data array will contain the
+    following values:
+
+		BITS    COMMENTS
+    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+    data[1] = bxxx xxxx Left button and x-axis motion.
+    data[2] = byyy yyyy Right button and y-axis motion.
+    data[3] = ???? ???? unknown
+    data[4] = ???? ???? unknown
+
+  */
+
+	/* If it's a trackpad, we alias the second button to the first.
+	   NOTE: Apple sends an ADB flush command to the trackpad when
+	         the first (the real) button is released. We could do
+		 this here using async flush requests.
+	*/
+	switch (adbhid[id]->mouse_kind)
+	{
+	    case ADBMOUSE_TRACKPAD:
+		data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
+		data[2] = data[2] | 0x80;
+		break;
+	    case ADBMOUSE_MICROSPEED:
+		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
+			| (data[3] & 0x08);
+		break;
+	    case ADBMOUSE_TRACKBALLPRO:
+		data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
+			& ((data[3] & 0x08) << 4));
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
+		break;
+	    case ADBMOUSE_MS_A3:
+		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+		data[3] = ((data[3] & 0x04) << 5);
+		break;
+            case ADBMOUSE_MACALLY2:
+		data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
+		data[2] |= 0x80;  /* Right button is mapped as button 3 */
+		nb=4;
+                break;
+	}
+
+	input_report_key(&adbhid[id]->input, BTN_LEFT,   !((data[1] >> 7) & 1));
+	input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
+
+	if (nb >= 4)
+		input_report_key(&adbhid[id]->input, BTN_RIGHT,  !((data[3] >> 7) & 1));
+
+	input_report_rel(&adbhid[id]->input, REL_X,
+			 ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ));
+	input_report_rel(&adbhid[id]->input, REL_Y,
+			 ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 ));
+}
+
+static void
+adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
+	int id = (data[0] >> 4) & 0x0f;
+
+	if (!adbhid[id]) {
+		printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id);
+		return;
+	}
+
+	switch (adbhid[id]->original_handler_id) {
+	default:
+	case 0x02: /* Adjustable keyboard button device */
+		printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
+		       data[0], data[1], data[2], data[3]);
+		break;
+	case 0x1f: /* Powerbook button device */
+	  {
+#ifdef CONFIG_PMAC_BACKLIGHT
+		int backlight = get_backlight_level();
+
+		/*
+		 * XXX: Where is the contrast control for the passive?
+		 *  -- Cort
+		 */
+
+		switch (data[1]) {
+		case 0x8:	/* mute */
+			break;
+
+		case 0x7:	/* contrast decrease */
+			break;
+
+		case 0x6:	/* contrast increase */
+			break;
+
+		case 0xa:	/* brightness decrease */
+			if (backlight < 0)
+				break;
+			if (backlight > BACKLIGHT_OFF)
+				set_backlight_level(backlight-1);
+			else
+				set_backlight_level(BACKLIGHT_OFF);
+			break;
+
+		case 0x9:	/* brightness increase */
+			if (backlight < 0)
+				break;
+			if (backlight < BACKLIGHT_MAX)
+				set_backlight_level(backlight+1);
+			else 
+				set_backlight_level(BACKLIGHT_MAX);
+			break;
+		}
+#endif /* CONFIG_PMAC_BACKLIGHT */
+	  }
+	  break;
+	}
+}
+
+static struct adb_request led_request;
+static int leds_pending[16];
+static int pending_devs[16];
+static int pending_led_start=0;
+static int pending_led_end=0;
+
+static void real_leds(unsigned char leds, int device)
+{
+    if (led_request.complete) {
+	adb_request(&led_request, leds_done, 0, 3,
+		    ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
+		    ~leds);
+    } else {
+	if (!(leds_pending[device] & 0x100)) {
+	    pending_devs[pending_led_end] = device;
+	    pending_led_end++;
+	    pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
+	}
+	leds_pending[device] = leds | 0x100;
+    }
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here.
+ */
+static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct adbhid *adbhid = dev->private;
+	unsigned char leds;
+
+	switch (type) {
+	case EV_LED:
+	  leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0)
+	       | (test_bit(LED_NUML,    dev->led) ? 1 : 0)
+	       | (test_bit(LED_CAPSL,   dev->led) ? 2 : 0);
+	  real_leds(leds, adbhid->id);
+	  return 0;
+	}
+
+	return -1;
+}
+
+static void leds_done(struct adb_request *req)
+{
+    int leds,device;
+
+    if (pending_led_start != pending_led_end) {
+	device = pending_devs[pending_led_start];
+	leds = leds_pending[device] & 0xff;
+	leds_pending[device] = 0;
+	pending_led_start++;
+	pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
+	real_leds(leds,device);
+    }
+
+}
+
+static int
+adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
+{
+	unsigned long flags;
+
+	switch (code) {
+	case ADB_MSG_PRE_RESET:
+	case ADB_MSG_POWERDOWN:
+	    	/* Stop the repeat timer. Autopoll is already off at this point */
+		save_flags(flags);
+		cli();
+		{
+			int i;
+			for (i = 1; i < 16; i++) {
+				if (adbhid[i])
+					del_timer(&adbhid[i]->input.timer);
+			}
+		}
+		restore_flags(flags);
+
+		/* Stop pending led requests */
+		while(!led_request.complete)
+			adb_poll();
+		break;
+
+	case ADB_MSG_POST_RESET:
+		adbhid_probe();
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static void
+adbhid_input_register(int id, int default_id, int original_handler_id,
+		      int current_handler_id, int mouse_kind)
+{
+	int i;
+
+	if (adbhid[id]) {
+		printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id);
+		return;
+	}
+
+	if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL)))
+		return;
+
+	memset(adbhid[id], 0, sizeof(struct adbhid));
+
+	adbhid[id]->id = default_id;
+	adbhid[id]->original_handler_id = original_handler_id;
+	adbhid[id]->current_handler_id = current_handler_id;
+	adbhid[id]->mouse_kind = mouse_kind;
+	adbhid[id]->input.private = adbhid[id];
+	adbhid[id]->input.name = adbhid[id]->name;
+	adbhid[id]->input.idbus = BUS_ADB;
+	adbhid[id]->input.idvendor = 0x0001;
+	adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id;
+	adbhid[id]->input.idversion = 0x0100;
+
+	switch (default_id) {
+	case ADB_KEYBOARD:
+		if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) {
+			kfree(adbhid[id]);
+			return;
+		}
+
+		sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x",
+			id, default_id, original_handler_id);
+
+		memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes));
+
+		printk(KERN_INFO "Detected ADB keyboard, type ");
+		switch (original_handler_id) {
+		default:
+			printk("<unknown>.\n");
+			adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN;
+			break;
+
+		case 0x01: case 0x02: case 0x03: case 0x06: case 0x08:
+		case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C:
+		case 0xC0: case 0xC3: case 0xC6:
+			printk("ANSI.\n");
+			adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI;
+			break;
+
+		case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
+		case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
+		case 0xC4: case 0xC7:
+			printk("ISO, swapping keys.\n");
+			adbhid[id]->input.idversion = ADB_KEYBOARD_ISO;
+			i = adbhid[id]->keycode[10];
+			adbhid[id]->keycode[10] = adbhid[id]->keycode[50];
+			adbhid[id]->keycode[50] = i;
+			break;
+
+		case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A:
+		case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
+			printk("JIS.\n");
+			adbhid[id]->input.idversion = ADB_KEYBOARD_JIS;
+			break;
+		}
+
+		for (i = 0; i < 128; i++)
+			if (adbhid[id]->keycode[i])
+				set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit);
+
+		adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+		adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
+		adbhid[id]->input.event = adbhid_kbd_event;
+		adbhid[id]->input.keycodemax = 127;
+		adbhid[id]->input.keycodesize = 1;
+		break;
+
+	case ADB_MOUSE:
+		sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x",
+			id, default_id, original_handler_id);
+
+		adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+		adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+		adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+		break;
+
+	case ADB_MISC:
+		switch (original_handler_id) {
+		case 0x02: /* Adjustable keyboard button device */
+			sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x",
+				id, default_id, original_handler_id);
+			break;
+		case 0x1f: /* Powerbook button device */
+			sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x",
+				id, default_id, original_handler_id);
+			break;
+		}
+		if (adbhid[id]->name[0])
+			break;
+		/* else fall through */
+
+	default:
+		printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n");
+		kfree(adbhid[id]);
+		return;
+	}
+
+	adbhid[id]->input.keycode = adbhid[id]->keycode;
+
+	input_register_device(&adbhid[id]->input);
+
+	printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n",
+	       adbhid[id]->input.number, id, default_id, original_handler_id);
+
+	if (default_id == ADB_KEYBOARD) {
+		/* HACK WARNING!! This should go away as soon there is an utility
+		 * to control that for event devices.
+		 */
+		adbhid[id]->input.rep[REP_DELAY] = HZ/2;   /* input layer default: HZ/4 */
+		adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */
+	}
+}
+
+static void adbhid_input_unregister(int id)
+{
+	input_unregister_device(&adbhid[id]->input);
+	if (adbhid[id]->keycode)
+		kfree(adbhid[id]->keycode);
+	kfree(adbhid[id]);
+	adbhid[id] = 0;
+}
+
+
+static void
+adbhid_probe(void)
+{
+	struct adb_request req;
+	int i, default_id, org_handler_id, cur_handler_id;
+
+	for (i = 1; i < 16; i++) {
+		if (adbhid[i])
+			adbhid_input_unregister(i);
+	}
+
+	adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input);
+	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input);
+	adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input);
+
+	for (i = 0; i < keyboard_ids.nids; i++) {
+		int id = keyboard_ids.id[i];
+
+		adb_get_infos(id, &default_id, &org_handler_id);
+
+		/* turn off all leds */
+		adb_request(&req, NULL, ADBREQ_SYNC, 3,
+			    ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
+
+		/* Enable full feature set of the keyboard
+		   ->get it to send separate codes for left and right shift,
+		   control, option keys */
+#if 0		/* handler 5 doesn't send separate codes for R modifiers */
+		if (adb_try_handler_change(id, 5))
+			printk("ADB keyboard at %d, handler set to 5\n", id);
+		else
+#endif
+		if (adb_try_handler_change(id, 3))
+			printk("ADB keyboard at %d, handler set to 3\n", id);
+		else
+			printk("ADB keyboard at %d, handler 1\n", id);
+
+		adb_get_infos(id, &default_id, &cur_handler_id);
+		adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0);
+	}
+
+	for (i = 0; i < buttons_ids.nids; i++) {
+		int id = buttons_ids.id[i];
+
+		adb_get_infos(id, &default_id, &org_handler_id);
+		adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0);
+	}
+
+	/* Try to switch all mice to handler 4, or 2 for three-button
+	   mode and full resolution. */
+	for (i = 0; i < mouse_ids.nids; i++) {
+		int id = mouse_ids.id[i];
+		int mouse_kind;
+
+		adb_get_infos(id, &default_id, &org_handler_id);
+
+		if (adb_try_handler_change(id, 4)) {
+			printk("ADB mouse at %d, handler set to 4", id);
+			mouse_kind = ADBMOUSE_EXTENDED;
+		}
+		else if (adb_try_handler_change(id, 0x2F)) {
+			printk("ADB mouse at %d, handler set to 0x2F", id);
+			mouse_kind = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x42)) {
+			printk("ADB mouse at %d, handler set to 0x42", id);
+			mouse_kind = ADBMOUSE_TRACKBALLPRO;
+		}
+		else if (adb_try_handler_change(id, 0x66)) {
+			printk("ADB mouse at %d, handler set to 0x66", id);
+			mouse_kind = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x5F)) {
+			printk("ADB mouse at %d, handler set to 0x5F", id);
+			mouse_kind = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 3)) {
+			printk("ADB mouse at %d, handler set to 3", id);
+			mouse_kind = ADBMOUSE_MS_A3;
+		}
+		else if (adb_try_handler_change(id, 2)) {
+			printk("ADB mouse at %d, handler set to 2", id);
+			mouse_kind = ADBMOUSE_STANDARD_200;
+		}
+		else {
+			printk("ADB mouse at %d, handler 1", id);
+			mouse_kind = ADBMOUSE_STANDARD_100;
+		}
+
+		if ((mouse_kind == ADBMOUSE_TRACKBALLPRO)
+		    || (mouse_kind == ADBMOUSE_MICROSPEED)) {
+			init_microspeed(id);
+		} else if (mouse_kind == ADBMOUSE_MS_A3) {
+			init_ms_a3(id);
+		} else if (mouse_kind ==  ADBMOUSE_EXTENDED) {
+			/*
+			 * Register 1 is usually used for device
+			 * identification.  Here, we try to identify
+			 * a known device and call the appropriate
+			 * init function.
+			 */
+			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+				    ADB_READREG(id, 1));
+
+			if ((req.reply_len) &&
+			    (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
+			    	|| (req.reply[2] == 0x20))) {
+				mouse_kind = ADBMOUSE_TRACKBALL;
+				init_trackball(id);
+			}
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
+			    (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) {
+				mouse_kind = ADBMOUSE_TRACKPAD;
+				init_trackpad(id);
+			}
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
+			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) {
+				mouse_kind = ADBMOUSE_TURBOMOUSE5;
+				init_turbomouse(id);
+			}
+			else if ((req.reply_len == 9) &&
+			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
+			    (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) {
+				if (adb_try_handler_change(id, 0x42)) {
+					printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
+					mouse_kind = ADBMOUSE_MACALLY2;
+				}
+			}
+		}
+		printk("\n");
+
+		adb_get_infos(id, &default_id, &cur_handler_id);
+		adbhid_input_register(id, default_id, org_handler_id,
+				      cur_handler_id, mouse_kind);
+        }
+}
+
+static void 
+init_trackpad(int id)
+{
+	struct adb_request req;
+	unsigned char r1_buffer[8];
+
+	printk(" (trackpad)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+	ADB_READREG(id,1));
+	if (req.reply_len < 8)
+	    printk("bad length for reg. 1\n");
+	else
+	{
+	    memcpy(r1_buffer, &req.reply[1], 8);
+	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
+	        ADB_WRITEREG(id,1),
+	            r1_buffer[0],
+	            r1_buffer[1],
+	            r1_buffer[2],
+	            r1_buffer[3],
+	            r1_buffer[4],
+	            r1_buffer[5],
+	            0x0d, /*r1_buffer[6],*/
+	            r1_buffer[7]);
+
+            adb_request(&req, NULL, ADBREQ_SYNC, 9,
+	        ADB_WRITEREG(id,2),
+	    	    0x99,
+	    	    0x94,
+	    	    0x19,
+	    	    0xff,
+	    	    0xb2,
+	    	    0x8a,
+	    	    0x1b,
+	    	    0x50);
+	    
+	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
+	        ADB_WRITEREG(id,1),
+	            r1_buffer[0],
+	            r1_buffer[1],
+	            r1_buffer[2],
+	            r1_buffer[3],
+	            r1_buffer[4],
+	            r1_buffer[5],
+	            0x03, /*r1_buffer[6],*/
+	            r1_buffer[7]);
+        }
+}
+
+static void 
+init_trackball(int id)
+{
+	struct adb_request req;
+
+	printk(" (trackman/mouseman)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 00,0x81);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 01,0x81);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 02,0x81);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 03,0x38);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 00,0x81);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 01,0x81);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 02,0x81);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id,1), 03,0x38);
+}
+
+static void
+init_turbomouse(int id)
+{
+	struct adb_request req;
+
+        printk(" (TurboMouse 5)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 9,
+	ADB_WRITEREG(3,2),
+	    0xe7,
+	    0x8c,
+	    0,
+	    0,
+	    0,
+	    0xff,
+	    0xff,
+	    0x94);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 9,
+	ADB_WRITEREG(3,2),
+	    0xa5,
+	    0x14,
+	    0,
+	    0,
+	    0x69,
+	    0xff,
+	    0xff,
+	    0x27);
+}
+
+static void
+init_microspeed(int id)
+{
+	struct adb_request req;
+
+        printk(" (Microspeed/MacPoint or compatible)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	/* This will initialize mice using the Microspeed, MacPoint and
+	   other compatible firmware. Bit 12 enables extended protocol.
+	   
+	   Register 1 Listen (4 Bytes)
+            0 -  3     Button is mouse (set also for double clicking!!!)
+            4 -  7     Button is locking (affects change speed also)
+            8 - 11     Button changes speed
+           12          1 = Extended mouse mode, 0 = normal mouse mode
+           13 - 15     unused 0
+           16 - 23     normal speed
+           24 - 31     changed speed
+
+       Register 1 talk holds version and product identification information.
+       Register 1 Talk (4 Bytes):
+            0 -  7     Product code
+            8 - 23     undefined, reserved
+           24 - 31     Version number
+        
+       Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
+ */
+	adb_request(&req, NULL, ADBREQ_SYNC, 5,
+	ADB_WRITEREG(id,1),
+	    0x20,	/* alt speed = 0x20 (rather slow) */
+	    0x00,	/* norm speed = 0x00 (fastest) */
+	    0x10,	/* extended protocol, no speed change */
+	    0x07);	/* all buttons enabled as mouse buttons, no locking */
+
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
+static void
+init_ms_a3(int id)
+{
+	struct adb_request req;
+
+	printk(" (Mouse Systems A3 Mouse, or compatible)");
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+	ADB_WRITEREG(id, 0x2),
+	    0x00,
+	    0x07);
+ 
+ 	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
+static int __init adbhid_init(void)
+{
+	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+	    return 0;
+
+	led_request.complete = 1;
+
+	adbhid_probe();
+
+	notifier_chain_register(&adb_client_list, &adbhid_adb_notifier);
+
+	return 0;
+}
+
+static void adbhid_exit(void)
+{
+}
+ 
+module_init(adbhid_init);
+module_exit(adbhid_exit);
diff -urN linux-2.2.18-pre20/drivers/macintosh/mac_hid.c linux/drivers/macintosh/mac_hid.c
--- linux-2.2.18-pre20/drivers/macintosh/mac_hid.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/mac_hid.c	Mon Dec  3 22:14:16 2001
@@ -0,0 +1,492 @@
+/*
+ * drivers/macintosh/mac_hid.c
+ *
+ * HID support stuff for Macintosh computers.
+ *
+ * Copyright (C) 2000 Franz Sirl.
+ *
+ * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all
+ * major distributions are using the Linux keycodes.
+ * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/input.h>
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+#include <linux/keyboard.h>
+#include <asm/keyboard.h>
+#include <asm/machdep.h>
+#endif
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mac_hid_kbd_sysrq_xlate[128] =
+	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
+	"yt123465=97-80o]"				/* 0x10 - 0x1f */
+	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
+	"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
+							/* 0x30 - 0x3f */
+	"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
+							/* 0x40 - 0x4f */
+	"\000\0000123456789\000\000\000"		/* 0x50 - 0x5f */
+	"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
+							/* 0x60 - 0x6f */
+extern unsigned char pckbd_sysrq_xlate[128];
+#endif
+
+static u_short macplain_map[NR_KEYS] = {
+	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
+	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
+	0xfb79,	0xfb74,	0xf031,	0xf032,	0xf033,	0xf034,	0xf036,	0xf035,
+	0xf03d,	0xf039,	0xf037,	0xf02d,	0xf038,	0xf030,	0xf05d,	0xfb6f,
+	0xfb75,	0xf05b,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf027,
+	0xfb6b,	0xf03b,	0xf05c,	0xf02c,	0xf02f,	0xfb6e,	0xfb6d,	0xf02e,
+	0xf009,	0xf020,	0xf060,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf109,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
+	0xf101,	0xf119,	0xf100,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
+};
+
+static u_short macshift_map[NR_KEYS] = {
+	0xfb41,	0xfb53,	0xfb44,	0xfb46,	0xfb48,	0xfb47,	0xfb5a,	0xfb58,
+	0xfb43,	0xfb56,	0xf200,	0xfb42,	0xfb51,	0xfb57,	0xfb45,	0xfb52,
+	0xfb59,	0xfb54,	0xf021,	0xf040,	0xf023,	0xf024,	0xf05e,	0xf025,
+	0xf02b,	0xf028,	0xf026,	0xf05f,	0xf02a,	0xf029,	0xf07d,	0xfb4f,
+	0xfb55,	0xf07b,	0xfb49,	0xfb50,	0xf201,	0xfb4c,	0xfb4a,	0xf022,
+	0xfb4b,	0xf03a,	0xf07c,	0xf03c,	0xf03f,	0xfb4e,	0xfb4d,	0xf03e,
+	0xf009,	0xf020,	0xf07e,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf10e,	0xf10f,	0xf110,	0xf10c,	0xf111,	0xf112,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf203,	0xf200,	0xf113,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf20b,	0xf116,	0xf10d,	0xf117,
+	0xf10b,	0xf20a,	0xf10a,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
+};
+
+static u_short macaltgr_map[NR_KEYS] = {
+	0xf914,	0xfb73,	0xf917,	0xf919,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
+	0xf916,	0xfb76,	0xf200,	0xf915,	0xfb71,	0xfb77,	0xf918,	0xfb72,
+	0xfb79,	0xfb74,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
+	0xf200,	0xf05d,	0xf07b,	0xf05c,	0xf05b,	0xf07d,	0xf07e,	0xfb6f,
+	0xfb75,	0xf200,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf200,
+	0xfb6b,	0xf200,	0xf200,	0xf200,	0xf200,	0xfb6e,	0xfb6d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf90a,	0xf90b,	0xf90c,	0xf90d,	0xf90e,	0xf90f,
+	0xf910,	0xf911,	0xf200,	0xf912,	0xf913,	0xf200,	0xf200,	0xf200,
+	0xf510,	0xf511,	0xf512,	0xf50e,	0xf513,	0xf514,	0xf200,	0xf516,
+	0xf200,	0xf10c,	0xf200,	0xf202,	0xf200,	0xf515,	0xf200,	0xf517,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf50f,	0xf117,
+	0xf50d,	0xf119,	0xf50c,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
+};
+
+static u_short macctrl_map[NR_KEYS] = {
+	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
+	0xf019,	0xf014,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01e,	0xf01d,
+	0xf200,	0xf200,	0xf01f,	0xf01f,	0xf07f,	0xf200,	0xf01d,	0xf00f,
+	0xf015,	0xf01b,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf007,
+	0xf00b,	0xf200,	0xf01c,	0xf200,	0xf07f,	0xf00e,	0xf00d,	0xf20e,
+	0xf200,	0xf000,	0xf000,	0xf008,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf204,	0xf200,	0xf109,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
+	0xf101,	0xf119,	0xf100,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
+};
+
+static u_short macshift_ctrl_map[NR_KEYS] = {
+	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
+	0xf019,	0xf014,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf00f,
+	0xf015,	0xf200,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf200,
+	0xf00b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf00e,	0xf00d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf200,	0xf117,
+	0xf200,	0xf119,	0xf200,	0xf700,	0xf701,	0xf702,	0xf200,	0xf20c,
+};
+
+static u_short macalt_map[NR_KEYS] = {
+	0xf861,	0xf873,	0xf864,	0xf866,	0xf868,	0xf867,	0xf87a,	0xf878,
+	0xf863,	0xf876,	0xf200,	0xf862,	0xf871,	0xf877,	0xf865,	0xf872,
+	0xf879,	0xf874,	0xf831,	0xf832,	0xf833,	0xf834,	0xf836,	0xf835,
+	0xf83d,	0xf839,	0xf837,	0xf82d,	0xf838,	0xf830,	0xf85d,	0xf86f,
+	0xf875,	0xf85b,	0xf869,	0xf870,	0xf80d,	0xf86c,	0xf86a,	0xf827,
+	0xf86b,	0xf83b,	0xf85c,	0xf82c,	0xf82f,	0xf86e,	0xf86d,	0xf82e,
+	0xf809,	0xf820,	0xf860,	0xf87f,	0xf200,	0xf81b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf210,	0xf211,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf900,	0xf901,	0xf902,	0xf903,	0xf904,	0xf905,
+	0xf906,	0xf907,	0xf200,	0xf908,	0xf909,	0xf200,	0xf200,	0xf200,
+	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
+	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf509,	0xf200,	0xf50b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
+	0xf501,	0xf119,	0xf500,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
+};
+
+static u_short macctrl_alt_map[NR_KEYS] = {
+	0xf801,	0xf813,	0xf804,	0xf806,	0xf808,	0xf807,	0xf81a,	0xf818,
+	0xf803,	0xf816,	0xf200,	0xf802,	0xf811,	0xf817,	0xf805,	0xf812,
+	0xf819,	0xf814,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80f,
+	0xf815,	0xf200,	0xf809,	0xf810,	0xf201,	0xf80c,	0xf80a,	0xf200,
+	0xf80b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80e,	0xf80d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
+	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf509,	0xf200,	0xf50b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
+	0xf501,	0xf119,	0xf500,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
+};
+
+static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = {
+	macplain_map, macshift_map, macaltgr_map, 0,
+	macctrl_map, macshift_ctrl_map, 0, 0,
+	macalt_map, 0, 0, 0,
+	macctrl_alt_map,   0
+};
+
+static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS];
+
+int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+			  char raw_mode);
+static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+				   void *buffer, size_t *lenp);
+char mac_hid_kbd_unexpected_up(unsigned char keycode);
+
+static int keyboard_lock_keycodes = 0;
+int keyboard_sends_linux_keycodes = 0;
+#else
+int keyboard_sends_linux_keycodes = 1;
+#endif /* CONFIG_MAC_ADBKEYCODES */
+
+
+static unsigned char e0_keys[128] = {
+	0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0,		/* 0x00-0x07 */
+	0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0,			/* 0x08-0x0f */
+	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x10-0x17 */
+	0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0,		/* 0x18-0x1f */
+	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x20-0x27 */
+	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x28-0x2f */
+	0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ,		/* 0x30-0x37 */
+	KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0,			/* 0x38-0x3f */
+	0, 0, 0, 0, 0, 0, 0, KEY_HOME,				/* 0x40-0x47 */
+	KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */
+	KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */
+	0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */
+	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x60-0x67 */
+	0, 0, 0, 0, 0, 0, 0, KEY_MACRO,				/* 0x68-0x6f */
+	0, 0, 0, 0, 0, 0, 0, 0,					/* 0x70-0x77 */
+	0, 0, 0, 0, 0, 0, 0, 0					/* 0x78-0x7f */
+};
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+static struct input_dev emumousebtn;
+static void emumousebtn_input_register(void);
+static int mouse_emulate_buttons = 0;
+static int mouse_button2_keycode = KEY_RIGHTCTRL;	/* right control key */
+static int mouse_button3_keycode = KEY_RIGHTALT;	/* right option key */
+static int mouse_last_keycode = 0;
+#endif
+
+extern void pckbd_init_hw(void);
+
+#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+/* file(s) in /proc/sys/dev/mac_hid */
+ctl_table mac_hid_files[] =
+{
+#ifdef CONFIG_MAC_ADBKEYCODES
+  {
+    DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES,
+    "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int),
+    0644, NULL, &mac_hid_sysctl_keycodes
+  },
+  {
+    DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES,
+    "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int),
+    0644, NULL, &proc_dointvec
+  },
+#endif
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+  {
+    DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
+    "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int),
+    0644, NULL, &proc_dointvec
+  },
+  {
+    DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,
+    "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int),
+    0644, NULL, &proc_dointvec
+  },
+  {
+    DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,
+    "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int),
+    0644, NULL, &proc_dointvec
+  },
+#endif
+  { 0 }
+};
+
+/* dir in /proc/sys/dev */
+ctl_table mac_hid_dir[] =
+{
+  { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files },
+  { 0 }
+};
+
+/* /proc/sys/dev itself, in case that is not there yet */
+ctl_table mac_hid_root_dir[] =
+{
+  { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir },
+  { 0 }
+};
+
+static struct ctl_table_header *mac_hid_sysctl_header;
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+static
+int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+			    void *buffer, size_t *lenp)
+{
+	int val = keyboard_sends_linux_keycodes;
+	int ret = 0;
+
+	if (!write
+	    || (write && !keyboard_lock_keycodes))
+		ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+	if (write
+	    && keyboard_sends_linux_keycodes != val) {
+		if (!keyboard_sends_linux_keycodes) {
+#ifdef CONFIG_MAGIC_SYSRQ
+			ppc_md.ppc_kbd_sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
+			SYSRQ_KEY                = 0x69;
+#endif
+			memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
+			memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+		} else {
+#ifdef CONFIG_MAGIC_SYSRQ
+			ppc_md.ppc_kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+			SYSRQ_KEY                = 0x54;
+#endif
+			memcpy(mac_key_maps_save, key_maps, sizeof(key_maps));
+			memcpy(key_maps, pc_key_maps_save, sizeof(key_maps));
+		}
+	}
+
+	return ret;
+}
+#endif
+#endif /* endif CONFIG_SYSCTL */
+
+int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
+			  char raw_mode)
+{
+#ifdef CONFIG_MAC_ADBKEYCODES
+	if (!keyboard_sends_linux_keycodes) {
+		if (!raw_mode) {
+		/*
+		 * Convert R-shift/control/option to L version.
+		 */
+			switch (scancode) {
+			case 0x7b: scancode = 0x38; break; /* R-shift */
+			case 0x7c: scancode = 0x3a; break; /* R-option */
+			case 0x7d: scancode = 0x36; break; /* R-control */
+			}
+		}
+		*keycode = scancode;
+		return 1;
+	} else
+#endif
+	{
+		/* This code was copied from char/pc_keyb.c and will be
+		 * superflous when the input layer is fully integrated.
+		 * We don't need the high_keys handling, so this part
+		 * has been removed.
+		 */
+		static int prev_scancode = 0;
+
+		/* special prefix scancodes.. */
+		if (scancode == 0xe0 || scancode == 0xe1) {
+			prev_scancode = scancode;
+			return 0;
+		}
+
+		scancode &= 0x7f;
+
+		if (prev_scancode) {
+			if (prev_scancode != 0xe0) {
+				if (prev_scancode == 0xe1 && scancode == 0x1d) {
+					prev_scancode = 0x100;
+					return 0;
+				} else if (prev_scancode == 0x100 && scancode == 0x45) {
+					*keycode = KEY_PAUSE;
+					prev_scancode = 0;
+				} else {
+					if (!raw_mode)
+						printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+					prev_scancode = 0;
+					return 0;
+				}
+			} else {
+				prev_scancode = 0;
+				if (scancode == 0x2a || scancode == 0x36)
+					return 0;
+			}
+			if (e0_keys[scancode])
+				*keycode = e0_keys[scancode];
+			else {
+				if (!raw_mode)
+					printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+					       scancode);
+				return 0;
+			}
+		} else {
+			switch (scancode) {
+			case  91: scancode = KEY_LINEFEED; break;
+			case  92: scancode = KEY_KPEQUAL; break;
+			case 125: scancode = KEY_INTL1; break;
+			}
+			*keycode = scancode;
+		}
+		return 1;
+	}
+}
+
+char mac_hid_kbd_unexpected_up(unsigned char keycode)
+{
+	if (keyboard_sends_linux_keycodes && keycode == KEY_F13)
+		return 0;
+	else
+		return 0x80;
+}
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+int mac_hid_keyboard_sends_linux_keycodes(void)
+{
+	return keyboard_sends_linux_keycodes;
+}
+
+static int __init mac_hid_setup(char *str)
+{
+	int ints[11];
+
+	str = get_options(str, ints);
+	if (ints[0] == 1) {
+		keyboard_sends_linux_keycodes = ints[1] != 0;
+		keyboard_lock_keycodes = 1;
+	}
+	return 1;
+}
+
+__setup("keyboard_sends_linux_keycodes=", mac_hid_setup);
+
+#endif
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
+{
+	switch (caller) {
+	case 1:
+		/* Called from keybdev.c */
+		if (mouse_emulate_buttons
+		    && (keycode == mouse_button2_keycode
+			|| keycode == mouse_button3_keycode)) {
+			if (mouse_emulate_buttons == 1) {
+			 	input_report_key(&emumousebtn,
+						 keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
+						 down);
+				return 1;
+			}
+			mouse_last_keycode = down ? keycode : 0;
+		}
+		break;
+	case 2:
+		/* Called from mousedev.c */
+		if (mouse_emulate_buttons == 2 && keycode == 0) {
+			if (mouse_last_keycode == mouse_button2_keycode)
+				return 1; /* map to middle button */
+			if (mouse_last_keycode == mouse_button3_keycode)
+				return 2; /* map to right button */
+		}
+		return keycode; /* keep button */
+	}
+	return 0;
+}
+
+static void emumousebtn_input_register(void)
+{
+	emumousebtn.name = "Macintosh mouse button emulation";
+
+	emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+	emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+	emumousebtn.idbus = BUS_ADB;
+	emumousebtn.idvendor = 0x0001;
+	emumousebtn.idproduct = 0x0001;
+	emumousebtn.idversion = 0x0100;
+
+	input_register_device(&emumousebtn);
+
+	printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number);
+}
+#endif
+
+void __init mac_hid_init_hw(void)
+{
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+	memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
+
+	if (!keyboard_sends_linux_keycodes)
+		memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+#endif
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+	emumousebtn_input_register();
+#endif
+
+#if CONFIG_PPC
+	if (_machine != _MACH_Pmac)
+		pckbd_init_hw();
+#endif
+
+#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+	mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
+#endif /* CONFIG_SYSCTL */
+}
diff -urN linux-2.2.18-pre20/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- linux-2.2.18-pre20/drivers/macintosh/mac_keyb.c	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/mac_keyb.c	Mon Dec  3 22:14:16 2001
@@ -16,7 +16,7 @@
  *
  * - Standard 1 button mouse
  * - All standard Apple Extended protocol (handler ID 4)
- * - mouseman and trackman mice & trackballs 
+ * - mouseman and trackman mice & trackballs
  * - PowerBook Trackpad (default setup: enable tapping)
  * - MicroSpeed mouse & trackball (needs testing)
  * - CH Products Trackball Pro (needs testing)
@@ -48,10 +48,16 @@
 #include <asm/cuda.h>
 #include <asm/pmu.h>
 #include <asm/init.h>
+#include <asm/machdep.h>
+#include <asm/backlight.h>
 
 #include <linux/kbd_kern.h>
 #include <linux/kbd_ll.h>
 
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
 #define KEYB_KEYREG	0	/* register # for key up/down data */
 #define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
@@ -226,7 +232,7 @@
 
 
 static void kbd_repeat(unsigned long);
-static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static struct timer_list repeat_timer = { function: kbd_repeat };
 static int last_keycode;
 
 static void mackeyb_probe(void);
@@ -347,7 +353,7 @@
 #ifdef CONFIG_ADBMOUSE
 	/*
 	 * XXX: Add mouse button 2+3 fake codes here if mouse open.
-	 *	Keep track of 'button' states here as we only send 
+	 *	Keep track of 'button' states here as we only send
 	 *	single up/down events!
 	 *	Really messy; might need to check if keyboard is in
 	 *	VC_RAW mode.
@@ -587,61 +593,47 @@
 }
 #endif /* CONFIG_ADBMOUSE */
 
-/* XXX Needs to get rid of this, see comments in pmu.c */
-extern int backlight_level;
-
 static void
 buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
 {
+	int backlight = get_backlight_level();
+
 	/*
 	 * XXX: Where is the contrast control for the passive?
 	 *  -- Cort
 	 */
-	 
+
 	/* Ignore data from register other than 0 */
-	if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
+	if ((data[0] & 0x3) || (nb < 2))
 		return;
 
-	switch (data[1]&0xf )
-	{
-		/* mute */
-		case 0x8:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-			}
-			break;
-		/* contrast decrease */
-		case 0x7:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-			}
-			break;
-		/* contrast increase */
-		case 0x6:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-			}
-			break;
-		/* brightness decrease */
-		case 0xa:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-				if (backlight_level > 2)
-					pmu_set_brightness(backlight_level-2);
-				else
-					pmu_set_brightness(0);
-			}
+	switch (data[1]) {
+	case 0x8:		/* mute */
+		break;
+
+	case 0x7:		/* contrast decrease */
+		break;
+
+	case 0x6:		/* contrast increase */
+		break;
+
+	case 0xa:		/* brightness decrease */
+		if (backlight < 0)
 			break;
-		/* brightness increase */
-		case 0x9:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-				if (backlight_level < 0x1e)
-					pmu_set_brightness(backlight_level+2);
-				else 
-					pmu_set_brightness(0x1f);
-			}
+		if (backlight > BACKLIGHT_OFF)
+			set_backlight_level(backlight-1);
+		else
+			set_backlight_level(BACKLIGHT_OFF);
+		break;
+
+	case 0x9:		/* brightness increase */
+		if (backlight < 0)
 			break;
+		if (backlight < BACKLIGHT_MAX)
+			set_backlight_level(backlight+1);
+		else 
+			set_backlight_level(BACKLIGHT_MAX);
+		break;
 	}
 }
 
@@ -702,10 +694,10 @@
 
 }
 
-__initfunc(void mackbd_init_hw(void))
+void __init mackbd_init_hw(void)
 {
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-	    return;
+		return;
 
 	/* setup key map */
 	memcpy(key_maps[0], macplain_map, sizeof(plain_map));
@@ -736,7 +728,7 @@
 	switch (code) {
 	case ADB_MSG_PRE_RESET:
 	case ADB_MSG_POWERDOWN:
-	    	/* Stop the repeat timer. Autopoll is already off at this point */
+		/* Stop the repeat timer. Autopoll is already off at this point */
 		save_flags(flags);
 		cli();
 		del_timer(&repeat_timer);
@@ -842,7 +834,7 @@
 
 			if ((req.reply_len) &&
 			    (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
-			    	|| (req.reply[2] == 0x20)))
+				|| (req.reply[2] == 0x20)))
 				init_trackball(id);
 			else if ((req.reply_len >= 4) &&
 			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
@@ -865,7 +857,7 @@
         }
 }
 
-static void 
+static void
 init_trackpad(int id)
 {
 	struct adb_request req;
@@ -895,15 +887,15 @@
 
             adb_request(&req, NULL, ADBREQ_SYNC, 9,
 	        ADB_WRITEREG(id,2),
-	    	    0x99,
-	    	    0x94,
-	    	    0x19,
-	    	    0xff,
-	    	    0xb2,
-	    	    0x8a,
-	    	    0x1b,
-	    	    0x50);
-	    
+		    0x99,
+		    0x94,
+		    0x19,
+		    0xff,
+		    0xb2,
+		    0x8a,
+		    0x1b,
+		    0x50);
+
 	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
 	        ADB_WRITEREG(id,1),
 	            r1_buffer[0],
@@ -917,7 +909,7 @@
         }
 }
 
-static void 
+static void
 init_trackball(int id)
 {
 	struct adb_request req;
@@ -1000,7 +992,7 @@
 
 	/* This will initialize mice using the Microspeed, MacPoint and
 	   other compatible firmware. Bit 12 enables extended protocol.
-	   
+
 	   Register 1 Listen (4 Bytes)
             0 -  3     Button is mouse (set also for double clicking!!!)
             4 -  7     Button is locking (affects change speed also)
@@ -1015,7 +1007,7 @@
             0 -  7     Product code
             8 - 23     undefined, reserved
            24 - 31     Version number
-        
+
        Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
  */
 	adb_request(&req, NULL, ADBREQ_SYNC, 5,
@@ -1039,7 +1031,7 @@
 	ADB_WRITEREG(id, 0x2),
 	    0x00,
 	    0x07);
- 
+
  	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
  }
 
diff -urN linux-2.2.18-pre20/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- linux-2.2.18-pre20/drivers/macintosh/macserial.c	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/macserial.c	Mon Dec  3 22:14:16 2001
@@ -953,6 +953,67 @@
 	info->dma_initted = 1;
 }
 
+/*
+ * FixZeroBug....Works around a bug in the SCC receving channel.
+ * Taken from Darwin code, 15 Sept. 2000  -DanM
+ *
+ * The following sequence prevents a problem that is seen with O'Hare ASICs
+ * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
+ * at the input to the receiver becomes 'stuck' and locks up the receiver.
+ * This problem can occur as a result of a zero bit at the receiver input
+ * coincident with any of the following events:
+ *
+ *	The SCC is initialized (hardware or software).
+ *	A framing error is detected.
+ *	The clocking option changes from synchronous or X1 asynchronous
+ *		clocking to X16, X32, or X64 asynchronous clocking.
+ *	The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
+ *
+ * This workaround attempts to recover from the lockup condition by placing
+ * the SCC in synchronous loopback mode with a fast clock before programming
+ * any of the asynchronous modes.
+ */
+static void fix_zero_bug_scc(struct mac_serial * info)
+{
+	write_zsreg(info->zs_channel, 9,
+		    (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
+	udelay(10);
+	write_zsreg(info->zs_channel, 9,
+		    ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
+
+	write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
+
+	/* I think this is wrong....but, I just copying code....
+	*/
+	write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
+
+	write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
+	write_zsreg(info->zs_channel, 9, NV);	/* Didn't we already do this? */
+	write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
+	write_zsreg(info->zs_channel, 12, 0);
+	write_zsreg(info->zs_channel, 13, 0);
+	write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
+	write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
+	write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
+	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+	write_zsreg(info->zs_channel, 0, RES_EXT_INT);	/* to kill some time */
+
+	/* The channel should be OK now, but it is probably receiving
+	 * loopback garbage.
+	 * Switch to asynchronous mode, disable the receiver,
+	 * and discard everything in the receive buffer.
+	 */
+	write_zsreg(info->zs_channel, 9, NV);
+	write_zsreg(info->zs_channel, 4, PAR_ENA);
+	write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
+
+	while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
+		(void)read_zsreg(info->zs_channel, 8);
+		write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+		write_zsreg(info->zs_channel, 0, ERR_RES);
+	}
+}
+
 static int setup_scc(struct mac_serial * info)
 {
 	unsigned long flags;
@@ -961,6 +1022,9 @@
 
 	save_flags(flags); cli(); /* Disable interrupts */
 
+	/* Nice buggy HW ... */
+	fix_zero_bug_scc(info);
+
 	/*
 	 * Reset the chip.
 	 */
@@ -1081,7 +1145,7 @@
 
 	info->curregs[5] &= ~TxENAB;
 	if (!info->tty || C_HUPCL(info->tty))
-		info->curregs[5] &= ~(DTR | RTS);
+		info->curregs[5] &= ~DTR;
 	info->pendregs[5] = info->curregs[5];
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 
@@ -1253,7 +1317,7 @@
 
 	/* assert DTR, wait 30ms, talk to the chip */
 	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
-	udelay(30000);
+	mdelay(30);
 	while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
 		read_zsdata(info->zs_channel);
 
@@ -1592,17 +1656,35 @@
 	if (C_CRTSCTS(tty)) {
 		/*
 		 * Here we want to turn off the RTS line.  On Macintoshes,
-		 * we only get the DTR line, which goes to both DTR and
-		 * RTS on the modem.  RTS doesn't go out to the serial
-		 * port socket.  So you should make sure your modem is
-		 * set to ignore DTR if you're using CRTSCTS.
+		 * the external serial ports using a DIN-8 or DIN-9
+		 * connector only have the DTR line (which is usually
+		 * wired to both RTS and DTR on an external modem in
+		 * the cable).  RTS doesn't go out to the serial port
+		 * socket, it acts as an output enable for the transmit
+		 * data line.  So in this case we don't drop RTS.
+		 *
+		 * Macs with internal modems generally do have both RTS
+		 * and DTR wired to the modem, so in that case we do
+		 * drop RTS.
 		 */
+		if (info->is_internal_modem) {
+			save_flags(flags); cli();
+			info->curregs[5] &= ~RTS;
+			info->pendregs[5] &= ~RTS;
+			write_zsreg(info->zs_channel, 5, info->curregs[5]);
+			restore_flags(flags);
+		}
+	}
+
+#ifdef CDTRCTS
+	if (tty->termios->c_cflag & CDTRCTS) {
 		save_flags(flags); cli();
-		info->curregs[5] &= ~(DTR | RTS);
-		info->pendregs[5] &= ~(DTR | RTS);
+		info->curregs[5] &= ~DTR;
+		info->pendregs[5] &= ~DTR;
 		write_zsreg(info->zs_channel, 5, info->curregs[5]);
 		restore_flags(flags);
 	}
+#endif /* CDTRCTS */
 }
 
 static void rs_unthrottle(struct tty_struct * tty)
@@ -1629,14 +1711,25 @@
 		restore_flags(flags);
 	}
 
-	if (C_CRTSCTS(tty)) {
-		/* Assert RTS and DTR lines */
+	if (C_CRTSCTS(tty) && info->is_internal_modem) {
+		/* Assert RTS line */
 		save_flags(flags); cli();
-		info->curregs[5] |= DTR | RTS;
-		info->pendregs[5] |= DTR | RTS;
+		info->curregs[5] |= RTS;
+		info->pendregs[5] |= RTS;
 		write_zsreg(info->zs_channel, 5, info->curregs[5]);
 		restore_flags(flags);
 	}
+
+#ifdef CDTRCTS
+	if (tty->termios->c_cflag & CDTRCTS) {
+		/* Assert DTR line */
+		save_flags(flags); cli();
+		info->curregs[5] |= DTR;
+		info->pendregs[5] |= DTR;
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+		restore_flags(flags);
+	}
+#endif
 }
 
 /*
@@ -2311,6 +2404,7 @@
 	/* setup misc varariables */
 	zss->kgdb_channel = 0;
 	zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+	zss->is_internal_modem = zss->is_cobalt_modem;
 
 	/* XXX tested only with wallstreet PowerBook,
 	   should do no harm anyway */
@@ -2318,8 +2412,12 @@
 	zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
 	/* 1999 Powerbook G3 has slot-names property instead */
 	slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
-	if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0)
-		zss->is_irda = 1;
+	if (slots && slots->count > 0) {
+		if (strcmp(slots->name, "IrDA") == 0)
+			zss->is_irda = 1;
+		else if (strcmp(slots->name, "Modem") == 0)
+			zss->is_internal_modem = 1;
+	}
 
 	if (zss->has_dma) {
 		zss->dma_priv = NULL;
@@ -2560,6 +2658,8 @@
 			printk(", port = %s", connector);
 		if (info->is_cobalt_modem)
 			printk(" (cobalt modem)");
+		else if (info->is_internal_modem)
+			printk(" (internal modem)");
 		if (info->is_irda)
 			printk(" (IrDA)");
 		printk("\n");
@@ -2898,7 +2998,7 @@
 /*
  *	Register console.
  */
-__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+__initfunc (long mac_scc_console_init(long kmem_start, long kmem_end))
 {
 	register_console(&sercons);
 	return kmem_start;
diff -urN linux-2.2.18-pre20/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- linux-2.2.18-pre20/drivers/macintosh/macserial.h	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/macserial.h	Mon Dec  3 22:14:16 2001
@@ -110,6 +110,7 @@
 	char break_abort;   /* Is serial console in, so process brk/abrt */
 	char kgdb_channel;  /* Kgdb is running on this channel */
 	char is_cons;       /* Is this our console. */
+	char is_internal_modem; /* is connected to an internal modem */
 	char is_cobalt_modem;	/* is a gatwick-based cobalt modem */
 	char is_irda;		/* is connected to an IrDA codec */
 	unsigned char tx_active; /* character is being xmitted */
diff -urN linux-2.2.18-pre20/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- linux-2.2.18-pre20/drivers/macintosh/mediabay.c	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/mediabay.c	Mon Dec  3 22:14:16 2001
@@ -474,8 +474,11 @@
 	    	} else if (MB_IDE_READY(i)) {
 			bay->timer = 0;
 			bay->state = mb_up;
-			if (bay->cd_index < 0)
+			if (bay->cd_index < 0) { 
+				pmu_suspend();
 				bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+				pmu_resume();
+			}
 			if (bay->cd_index == -1) {
 				/* We eventually do a retry */
 				bay->cd_retry++;
@@ -582,7 +585,7 @@
 
 #ifdef CONFIG_PMAC_PBOOK
 /*
- * notify clients before sleep and reset bus afterwards
+ * notify ents before sleep and reset bus afterwards
  */
 int
 mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
@@ -611,7 +614,9 @@
 			   they seem to help the 3400 get it right.
 			 */
 			feature_set(bay->dev_node, FEATURE_IOBUS_enable);
-			mdelay(MB_STABLE_DELAY);
+			/* Force MB power to 0 */
+			set_mb_power(i, 0);
+			mdelay(MB_POWER_DELAY);
 			if (!bay->pismo)
 				out_8(&bay->addr->contents, 0x70);
 			mdelay(MB_STABLE_DELAY);
@@ -621,7 +626,9 @@
 			bay->last_value = bay->content_id;
 			bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
 			bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+#ifdef CONFIG_BLK_DEV_IDE
 			bay->cd_retry = 0;
+#endif			
 			do {
 				mdelay(1000/HZ);
 				media_bay_step(i);
diff -urN linux-2.2.18-pre20/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c
--- linux-2.2.18-pre20/drivers/macintosh/nvram.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/nvram.c	Mon Dec  3 22:14:16 2001
@@ -14,6 +14,7 @@
 #include <linux/nvram.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
+#include <asm/nvram.h>
 
 #define NVRAM_SIZE	8192
 
@@ -76,6 +77,30 @@
 	return p - buf;
 }
 
+static int nvram_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	switch(cmd) {
+		case PMAC_NVRAM_GET_OFFSET:
+		{
+			int part, offset;
+			if (copy_from_user(&part,(void*)arg,sizeof(part))!=0)
+				return -EFAULT;
+			if (part < pmac_nvram_OF || part > pmac_nvram_NR)
+				return -EINVAL;
+			offset = pmac_get_partition(part);
+			if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0)
+				return -EFAULT;
+			break;
+		}
+
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int nvram_open(struct inode *inode, struct file *file)
 {
 	MOD_INC_USE_COUNT;
@@ -94,7 +119,7 @@
 	write_nvram,
 	NULL,		/* nvram_readdir */
 	NULL,		/* nvram_select */
-	NULL,		/* nvram_ioctl */
+	nvram_ioctl,
 	NULL,		/* nvram_mmap */
 	nvram_open,
 	NULL,		/* flush */
diff -urN linux-2.2.18-pre20/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- linux-2.2.18-pre20/drivers/macintosh/via-pmu.c	Mon Sep  4 10:39:18 2000
+++ linux/drivers/macintosh/via-pmu.c	Mon Dec  3 22:14:16 2001
@@ -3,19 +3,17 @@
  *
  * The VIA (versatile interface adapter) interfaces to the PMU,
  * a 6805 microprocessor core whose primary function is to control
- * battery charging and system power on the PowerBook 3400 and 2400.
- * The PMU also controls the ADB (Apple Desktop Bus) which connects
+ * battery charging and system power on the PowerBooks and new
+ * "Core99" Apple machines.
+ * The PMU may also controls the ADB (Apple Desktop Bus) which connects
  * to the keyboard and mouse, as well as the non-volatile RAM
  * and the RTC (real time clock) chip.
  *
- * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
- * 
- * todo: - Check this driver for smp safety (new Core99 motherboards).
- *       - Cleanup synchro between VIA interrupt and GPIO-based PMU
- *         interrupt.
- *
- *
+ * Copyright (C) 1998 Paul Mackerras, Fabio Riccardi
+ *                    and Benjamin Herrenschmidt
+ *                    
  */
+ 
 #include <stdarg.h>
 #include <linux/config.h>
 #include <linux/types.h>
@@ -40,6 +38,10 @@
 #include <asm/feature.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
+#include <asm/backlight.h>
+
+#define DEBUG_SLEEP
+#define PMU_CORE99_SLEEP	/* Doesn't work yet (almost there...) */
 
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR	154
@@ -103,9 +105,11 @@
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
-static int pmu_has_adb, pmu_has_backlight;
+static int pmu_has_adb;
 static unsigned char *gpio_reg = NULL;
 static int gpio_irq = -1;
+static int pmu_suspended = 0;
+static spinlock_t pmu_lock;
 
 int asleep;
 
@@ -124,6 +128,8 @@
 			    struct pt_regs *regs);
 static void set_volume(int level);
 static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
+static int pmu_set_backlight_level(int level, void* data);
+static int pmu_set_backlight_enable(int on, int level, void* data);
 #ifdef CONFIG_PMAC_PBOOK
 static void pmu_pass_intr(unsigned char *data, int len);
 #endif
@@ -137,8 +143,10 @@
 };
 
 extern void low_sleep_handler(void);
-extern void sleep_save_intrs(int);
-extern void sleep_restore_intrs(void);
+extern void pmac_sleep_save_intrs(int);
+extern void pmac_sleep_restore_intrs(void);
+extern void openpic_sleep_save_intrs(void);
+extern void openpic_sleep_restore_intrs(void);
 
 extern int grackle_pcibios_read_config_word(unsigned char bus,
 	unsigned char dev_fn, unsigned char offset, unsigned short *val);
@@ -146,12 +154,18 @@
 extern int grackle_pcibios_write_config_word(unsigned char bus,
 	unsigned char dev_fn, unsigned char offset, unsigned short val);
 
+#ifdef DEBUG_SLEEP
+int pmu_polled_request(struct adb_request *req);
+int pmu_wink(struct adb_request *req);
+#endif
+
+
 /*
  * This table indicates for each PMU opcode:
  * - the number of data bytes to be sent with the command, or -1
  *   if a length byte should be sent,
  * - the number of response bytes which the PMU will return, or
- *   -1 if it will send a length byte.
+ *   -1 if it will send a length byte
  */
 static s8 pmu_data_len[256][2] __openfirmwaredata = {
 /*	   0	   1	   2	   3	   4	   5	   6	   7  */
@@ -197,6 +211,11 @@
 	"Core99"
 };
 
+static struct backlight_controller pmu_backlight_controller = {
+	pmu_set_backlight_enable,
+	pmu_set_backlight_level
+};
+
 int __openfirmware
 find_via_pmu()
 {
@@ -226,8 +245,9 @@
 			return 0;
 	}
 
+	spin_lock_init(&pmu_lock);
+
 	pmu_has_adb = 1;
-	pmu_has_backlight = 1;
 
 	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
 	    || device_is_compatible(vias->parent, "ohare")))
@@ -241,7 +261,6 @@
 
 		pmu_kind = PMU_KEYLARGO_BASED;
 		pmu_has_adb = (find_type_devices("adb") != NULL);
-		pmu_has_backlight = 0; /* Not driven by PMU */
 
 		gpiop = find_devices("gpio");
 		if (gpiop && gpiop->n_addrs) {
@@ -301,7 +320,7 @@
 	pmu_fully_inited = 1;
 
 	/* Enable backlight */
-	pmu_enable_backlight(1);
+	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
 
 	/* Make sure PMU settle down before continuing */
 	do {
@@ -318,7 +337,7 @@
 	out_8(&via[B], via[B] | TREQ);			/* negate TREQ */
 	out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK);	/* TACK in, TREQ out */
 
-	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff);
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
 	timeout =  100000;
 	while (!req.complete) {
 		if (--timeout < 0) {
@@ -349,7 +368,7 @@
 		while (!req.complete)
 			pmu_poll();
 	}
-
+		
 	return 1;
 }
 
@@ -553,8 +572,8 @@
 	req->next = 0;
 	req->sent = 0;
 	req->complete = 0;
-	save_flags(flags); cli();
 
+	spin_lock_irqsave(&pmu_lock, flags);
 	if (current_req != 0) {
 		last_req->next = req;
 		last_req = req;
@@ -565,7 +584,7 @@
 			pmu_start();
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&pmu_lock, flags);
 	return 0;
 }
 
@@ -639,35 +658,90 @@
 void __openfirmware
 pmu_poll()
 {
-	int ie;
-
+	if (!via)
+		return;
 	if (disable_poll)
 		return;
-	ie = _disable_interrupts();
-	if ((via[IFR] & (SR_INT | CB1_INT)) ||
-		(gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
+	/* Kicks ADB read when PMU is suspended */
+	if (pmu_suspended)
+		adb_int_pending = 1;
+	do {
 		via_pmu_interrupt(0, 0, 0);
-	_enable_interrupts(ie);
+	} while (pmu_suspended && (adb_int_pending || pmu_state != idle
+		|| req_awaiting_reply));
 }
 
-/* This function loops until the PMU is idle, to avoid spurrious shutdowns
- * when prom.c scrollscreen or xmon spends too much time without interupts
- * while some PMU communication is going on
+/* This function loops until the PMU is idle and prevents it from
+ * anwsering to ADB interrupts. pmu_request can still be called.
+ * This is done to avoid spurrious shutdowns when we know we'll have
+ * interrupts switched off for a long time
  */
 void __openfirmware
-pmu_safe_poll(void)
+pmu_suspend(void)
 {
-	int ie;
+#ifdef SUSPEND_USES_PMU
+	struct adb_request *req;
+#endif
+	unsigned long flags;
 
-	if (!via || disable_poll)
+	if (!via)
 		return;
+	
+	spin_lock_irqsave(&pmu_lock, flags);
+	pmu_suspended++;
+	if (pmu_suspended != 1) {
+		spin_unlock_irqrestore(&pmu_lock, flags);
+		return;
+	}
+
 	do {
-		ie = _disable_interrupts();
-		if ((via[IFR] & (SR_INT | CB1_INT)) ||
-			(gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
-			via_pmu_interrupt(0, 0, 0);
-		_enable_interrupts(ie);
-	} while (adb_int_pending || pmu_state != idle);
+		spin_unlock(&pmu_lock);
+		via_pmu_interrupt(0, 0, 0);
+		spin_lock(&pmu_lock);
+		if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
+#ifdef SUSPEND_USES_PMU
+			pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
+			spin_unlock_irqrestore(&pmu_lock, flags);
+			while(!req.complete)
+				pmu_poll();
+#else /* SUSPEND_USES_PMU */
+			if (gpio_irq >= 0)
+				disable_irq(gpio_irq);
+			out_8(&via[IER], CB1_INT | IER_CLR);
+			spin_unlock_irqrestore(&pmu_lock, flags);
+#endif /* SUSPEND_USES_PMU */
+			break;
+		}
+	} while (1);
+}
+
+void __openfirmware
+pmu_resume(void)
+{
+	unsigned long flags;
+	
+	if (!via || pmu_suspended < 1)
+		return;
+	
+	spin_lock_irqsave(&pmu_lock, flags);
+	pmu_suspended--;
+	if (pmu_suspended > 0) {
+		spin_unlock_irqrestore(&pmu_lock, flags);
+		return;
+	}
+	adb_int_pending = 1;
+#ifdef SUSPEND_USES_PMU
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+	spin_unlock_irqrestore(&pmu_lock, flags);
+	while(!req.complete)
+		pmu_poll();
+#else /* SUSPEND_USES_PMU */
+	if (gpio_irq >= 0)
+		enable_irq(gpio_irq);
+	out_8(&via[IER], CB1_INT | IER_SET);
+	spin_unlock_irqrestore(&pmu_lock, flags);
+	pmu_poll();
+#endif /* SUSPEND_USES_PMU */
 }
 
 static void __openfirmware
@@ -680,8 +754,9 @@
 	/* Currently, we use brute-force cli() for syncing with GPIO
 	 * interrupt. I'll make this smarter later, along with some
 	 * spinlocks for SMP */
-	save_flags(flags);cli();
+	spin_lock_irqsave(&pmu_lock, flags);
 	++disable_poll;
+	
 	while ((intr = in_8(&via[IFR])) != 0) {
 		if (++nloop > 1000) {
 			printk(KERN_DEBUG "PMU: stuck in intr loop, "
@@ -699,9 +774,15 @@
 			out_8(&via[IFR], intr);
 		}
 	}
+	/* This is not necessary except if synchronous ADB requests are done
+	 * with interrupts off, which should not happen. Since I'm not sure
+	 * this "wiring" will remain, I'm commenting it out for now. Please do
+	 * not remove. -- BenH.
+	 */
+#if 0
 	if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)
 		adb_int_pending = 1;
-
+#endif
 	if (pmu_state == idle) {
 		if (adb_int_pending) {
 			pmu_state = intack;
@@ -713,16 +794,17 @@
 		}
 	}
 	--disable_poll;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&pmu_lock, flags);
 }
 
 
 static void __openfirmware
 gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
+	adb_int_pending = 1;
 	via_pmu_interrupt(0, 0, 0);
 }
-
+ 
 static void __openfirmware
 pmu_sr_intr(struct pt_regs *regs)
 {
@@ -749,7 +831,7 @@
 	/* if reading grab the byte, and reset the interrupt */
 	if (pmu_state == reading || pmu_state == reading_intr)
 		bite = in_8(&via[SR]);
-
+	
 	out_8(&via[IFR], SR_INT);
 
 	switch (pmu_state) {
@@ -771,8 +853,11 @@
 			current_req = req->next;
 			if (req->reply_expected)
 				req_awaiting_reply = req;
-			else
+			else {
+				spin_unlock(&pmu_lock);
 				pmu_done(req);
+				spin_lock(&pmu_lock);
+			}
 		} else {
 			pmu_state = reading;
 			data_index = 0;
@@ -797,7 +882,8 @@
 				printk(KERN_ERR "PMU: bad reply len %d\n",
 				       bite);
 		} else {
-			reply_ptr[data_index++] = bite;
+			if (data_index < 32)
+				reply_ptr[data_index++] = bite;
 		}
 		if (data_index < data_len) {
 			recv_byte();
@@ -810,7 +896,9 @@
 			req = current_req;
 			current_req = req->next;
 			req->reply_len += data_index;
+			spin_unlock(&pmu_lock);
 			pmu_done(req);
+			spin_lock(&pmu_lock);
 		}
 		pmu_state = idle;
 
@@ -877,7 +965,7 @@
 		}
 	} else if (data[0] == 0x08 && len == 3) {
 		/* sound/brightness buttons pressed */
-		pmu_set_brightness(data[1] >> 3);
+		set_backlight_level(data[1] >> 4);
 		set_volume(data[2]);
 	} else {
 #ifdef CONFIG_PMAC_PBOOK
@@ -886,53 +974,22 @@
 	}
 }
 
-int backlight_level = -1;
-int backlight_enabled = 0;
-
-#define LEVEL_TO_BRIGHT(lev)	((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
-
-void __openfirmware
-pmu_enable_backlight(int on)
+static int backlight_to_bright[] = {
+	0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
+	0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
+};
+ 
+static int __openfirmware
+pmu_set_backlight_enable(int on, int level, void* data)
 {
 	struct adb_request req;
+	
+	if (vias == NULL)
+		return -ENODEV;
 
-	if ((vias == NULL) || !pmu_has_backlight)
-		return;
-
-	/* first call: get current backlight value */
-	if (on && backlight_level < 0) {
-		switch (pmu_kind) {
-		case PMU_OHARE_BASED:
-			pmu_request(&req, NULL, 2, 0xd9, 0);
-			while (!req.complete)
-				pmu_poll();
-			backlight_level = req.reply[1] >> 3;
-			break;
-		case PMU_HEATHROW_BASED:
-			/* We cannot use nvram_read_byte here (not yet initialized) */
-			pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
-			while (!req.complete)
-				pmu_poll();
-			backlight_level = req.reply[1];
-			printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
-			break;
-		case PMU_PADDINGTON_BASED:
-		case PMU_KEYLARGO_BASED:
-			/* the G3 PB 1999 has a backlight node
-			   and chrp-structured nvram */
-			/* XXX should read macos's "blkt" property in nvram
-			   for this node.  For now this ensures that the
-			   backlight doesn't go off as soon as linux boots. */
-			backlight_level = 20;
-			break;
-		default:
-		        backlight_enabled = 0;
-		        return;
-		}
-	}
 	if (on) {
 		pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
-			    LEVEL_TO_BRIGHT(backlight_level));
+			    backlight_to_bright[level]);
 		while (!req.complete)
 			pmu_poll();
 	}
@@ -940,34 +997,26 @@
 		    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
 	while (!req.complete)
 		pmu_poll();
-	backlight_enabled = on;
+
+	return 0;
 }
 
-void __openfirmware
-pmu_set_brightness(int level)
+static int __openfirmware
+pmu_set_backlight_level(int level, void* data)
 {
-	int bright;
+	if (vias == NULL)
+		return -ENODEV;
 
-	if ((vias == NULL) || !pmu_has_backlight)
-		return ;
+	if (!bright_req_1.complete)
+		return -EAGAIN;
+	pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+		backlight_to_bright[level]);
+	if (!bright_req_2.complete)
+		return -EAGAIN;
+	pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT
+		| (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF));
 
-	backlight_level = level;
-	bright = LEVEL_TO_BRIGHT(level);
-	if (!backlight_enabled)
-		return;
-	if (bright_req_1.complete)
-		pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
-		    bright);
-	if (bright_req_2.complete)
-		pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
-		    PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
-
-	/* XXX nvram address is hard-coded and looks ok on wallstreet, please
-	   test on your machine. Note that newer MacOS system software may break
-	   the nvram layout. */
-	if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete)
-		pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM,
-			    0x14, 0xe, level);
+	return 0;
 }
 
 void __openfirmware
@@ -1083,7 +1132,7 @@
 			       when, current, current->notifier_call);
 			for (; list != &sleep_notifiers; list = list->next) {
 				current = list_entry(list, struct pmu_sleep_notifier, list);
-				current->notifier_call(current, fallback);
+					current->notifier_call(current, fallback);
 			}
 			return ret;
 		}
@@ -1178,21 +1227,40 @@
 	}
 }
 
-#if 0
+#ifdef DEBUG_SLEEP
 /* N.B. This doesn't work on the 3400 */
-void pmu_blink(int n)
+void
+pmu_blink(int n)
 {
 	struct adb_request req;
 
+	memset(&req, 0, sizeof(req));
+	
 	for (; n > 0; --n) {
-		pmu_request(&req, NULL, 4, 0xee, 4, 0, 1);
-		while (!req.complete) pmu_poll();
-		udelay(50000);
-		pmu_request(&req, NULL, 4, 0xee, 4, 0, 0);
-		while (!req.complete) pmu_poll();
-		udelay(50000);
+		req.nbytes = 4;
+		req.done = NULL;
+		req.data[0] = 0xee;
+		req.data[1] = 4;
+		req.data[2] = 0;
+		req.data[3] = 1;
+		req.reply[0] = ADB_RET_OK;
+		req.reply_len = 1;
+		req.reply_expected = 0;
+		pmu_polled_request(&req);
+		mdelay(50);
+		req.nbytes = 4;
+		req.done = NULL;
+		req.data[0] = 0xee;
+		req.data[1] = 4;
+		req.data[2] = 0;
+		req.data[3] = 0;
+		req.reply[0] = ADB_RET_OK;
+		req.reply_len = 1;
+		req.reply_expected = 0;
+		pmu_polled_request(&req);
+		mdelay(50);
 	}
-	udelay(50000);
+	mdelay(50);
 }
 #endif
 
@@ -1200,7 +1268,33 @@
  * Put the powerbook to sleep.
  */
  
-#define FEATURE_CTRL(base)	((unsigned int *)(base + 0x38))
+static u32 save_via[8];
+static void save_via_state(void)
+{
+	save_via[0] = in_8(&via[ANH]);
+	save_via[1] = in_8(&via[DIRA]);
+	save_via[2] = in_8(&via[B]);
+	save_via[3] = in_8(&via[DIRB]);
+	save_via[4] = in_8(&via[PCR]);
+	save_via[5] = in_8(&via[ACR]);
+	save_via[6] = in_8(&via[T1CL]);
+	save_via[7] = in_8(&via[T1CH]);
+}
+static void restore_via_state(void)
+{
+	out_8(&via[ANH], save_via[0]);
+	out_8(&via[DIRA], save_via[1]);
+	out_8(&via[B], save_via[2]);
+	out_8(&via[DIRB], save_via[3]);
+	out_8(&via[PCR], save_via[4]);
+	out_8(&via[ACR], save_via[5]);
+	out_8(&via[T1CL], save_via[6]);
+	out_8(&via[T1CH], save_via[7]);
+	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */
+	out_8(&via[IFR], 0x7f);				/* clear IFR */
+	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+}
+
 #define	GRACKLE_PM	(1<<7)
 #define GRACKLE_DOZE	(1<<5)
 #define	GRACKLE_NAP	(1<<4)
@@ -1208,20 +1302,12 @@
 
 int __openfirmware powerbook_sleep_G3(void)
 {
-	int ret;
 	unsigned long save_l2cr;
-	unsigned long save_fcr;
 	unsigned long wait;
 	unsigned short pmcr1;
-	struct adb_request sleep_req;
-	struct device_node *macio;
-	unsigned long macio_base = 0;
-
-	macio = find_devices("mac-io");
-	if (macio != 0 && macio->n_addrs > 0)
-		macio_base = (unsigned long)
-			ioremap(macio->addrs[0].address, 0x40);
-
+	struct adb_request req;
+	int ret, timeout;
+	
 	/* Notify device drivers */
 	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
 	if (ret != PBOOK_SLEEP_OK) {
@@ -1245,31 +1331,57 @@
 	}
 
 	/* Give the disks a little time to actually finish writing */
-	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+	for (wait = jiffies + HZ; time_before(jiffies, wait); )
 		mb();
 
-	/* Disable all interrupts except pmu */
-	sleep_save_intrs(vias->intrs[0].line);
+	/* Wait for completion of async backlight requests */
+	while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+		pmu_poll();
+	
+	/* Turn off various things. Darwin does some retry tests here... */
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
+	while (!req.complete)
+		pmu_poll();
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+		PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);
+	while (!req.complete)
+		pmu_poll();
+
+	/* Disable all interrupts */
+	pmac_sleep_save_intrs(-1);
+
+	/* Make sure the PMU is idle */
+	while (pmu_state != idle)
+		pmu_poll();
 
 	/* Make sure the decrementer won't interrupt us */
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
-#if 0
-	/* Save the state of PCI config space for some slots */
-	pbook_pci_save();
-#endif
+	/* Make sure any pending DEC interrupt occuring while we did
+	 * the above didn't re-enable the DEC */
+	mb();
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+	
+	/* Giveup the FPU */
+	if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0)
+		giveup_fpu(current);
+
+	/* We can now disable MSR_EE */
+	cli();
+
 	/* For 750, save backside cache setting and disable it */
 	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
 	if (save_l2cr)
 		_set_L2CR(0);
 
-	if (macio_base != 0) {
-		save_fcr = in_le32(FEATURE_CTRL(macio_base));
-		/* Check if this is still valid on older powerbooks */
-		out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL));
-	}
+	/* Ask the PMU to put us to sleep */
+	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+	while (!req.complete)
+		pmu_poll();
 
-	if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0)
-		giveup_fpu(current);
+	/* The VIA is supposed not to be restored correctly*/
+	save_via_state();
+	/* We shut down some HW */
+	feature_prepare_for_sleep();
 
 	grackle_pcibios_read_config_word(0,0,0x70,&pmcr1);
 	/* Apparently, MacOS uses NAP mode for Grackle ??? */
@@ -1277,15 +1389,6 @@
 	pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
 	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
 
-	/* Ask the PMU to put us to sleep */
-	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
-	while (!sleep_req.complete)
-		mb();
-
-	cli();
-	while (pmu_state != idle)
-		pmu_poll();
-
 	/* Call low-level ASM sleep handler */
 	low_sleep_handler();
 
@@ -1293,26 +1396,201 @@
 	grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1);
 	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
 	grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
+	
+	/* Restore things */
+	feature_wake_up();
+	restore_via_state();
+	
+	/* Restore L2 cache */
+	if (save_l2cr)
+ 		_set_L2CR(save_l2cr);
+	
+	/* Restore userland MMU context */
+	set_context(current->mm->context);
+
+	/* Re-enable DEC interrupts and kick DEC */
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+	sti();
+	asm volatile("mtdec %0" : : "r" (0x10000000));
+
+	/* Power things up */
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+	while (!req.complete)
+		pmu_poll();
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
+			PMU_POW0_ON|PMU_POW0_HARD_DRIVE);
+	while (!req.complete)
+		pmu_poll();
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+			PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
+	while (!req.complete)
+		pmu_poll();
+
+	/* ack all pending interrupts */
+	timeout = 100000;
+	interrupt_data[0] = 1;
+	while (interrupt_data[0] || pmu_state != idle) {
+		if (--timeout < 0)
+			break;
+		if (pmu_state == idle)
+			adb_int_pending = 1;
+		via_pmu_interrupt(0, 0, 0);
+		udelay(10);
+	}
+
+	/* reenable interrupt controller */
+	pmac_sleep_restore_intrs();
+
+	/* Leave some time for HW to settle down */
+	mdelay(100);
+
+	/* Notify drivers */
+	broadcast_wake();
+
+	return 0;
+}
+
+#ifdef PMU_CORE99_SLEEP
+
+/* Not finished yet */
+int __openfirmware powerbook_sleep_Core99(void)
+{
+	unsigned long save_l2cr;
+	unsigned long wait;
+	struct adb_request req;
+	int ret, timeout;
+
+	/* Notify device drivers */
+	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
+	if (ret != PBOOK_SLEEP_OK) {
+		printk("pmu: sleep rejected\n");
+		return -EBUSY;
+	}
+
+	/* Sync the disks. */
+	/* XXX It would be nice to have some way to ensure that
+	 * nobody is dirtying any new buffers while we wait.
+	 * BenH: Moved to _after_ sleep request and changed video
+	 * drivers to vmalloc() during sleep request. This way, all
+	 * vmalloc's are done before actual sleep of block drivers */
+	fsync_dev(0);
+
+	/* Sleep can fail now. May not be very robust but useful for debugging */
+	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+	if (ret != PBOOK_SLEEP_OK) {
+		printk("pmu: sleep failed\n");
+		return -EBUSY;
+	}
+
+	/* Give the disks a little time to actually finish writing */
+	for (wait = jiffies + HZ; time_before(jiffies, wait); )
+		mb();
+
+	/* Wait for completion of async backlight requests */
+	while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+		pmu_poll();
+
+	/* Tell PMU what events will wake us up */
+	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
+		0xff, 0xff);
+	while (!req.complete)
+		pmu_poll();
+	pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
+		0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN);
+	while (!req.complete)
+		pmu_poll();
+
+	/* Save & disable all interrupts */
+	openpic_sleep_save_intrs();
 
 	/* Make sure the PMU is idle */
 	while (pmu_state != idle)
 		pmu_poll();
 
-	sti();
-#if 0
-	/* According to someone from Apple, this should not be needed,
-	   at least not for all devices. Let's keep it for now until we
-	   have something that works. */
-	pbook_pci_restore();
-#endif
-	set_context(current->mm->context);
+	/* Make sure the decrementer won't interrupt us */
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+	/* Make sure any pending DEC interrupt occuring while we did
+	 * the above didn't re-enable the DEC */
+	mb();
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+	/* Giveup the FPU */
+	if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0)
+		giveup_fpu(current);
+
+	/* We can now disable MSR_EE */
+	cli();
+
+	/* For 750, save backside cache setting and disable it */
+	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
+	if (save_l2cr)
+		_set_L2CR(0);
+
+	/* Save the state of PCI config space for some slots */
+	// pbook_pci_save();
+
+	/* Ask the PMU to put us to sleep */
+	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+	while (!req.complete)
+		pmu_poll();
+
+	/* The VIA is supposed not to be restored correctly*/
+	save_via_state();
+
+	/* Shut down various ASICs. There's a chance that we can no longer
+	 * talk to the PMU after this, so I moved it to _after_ sending the
+	 * sleep command to it. Still need to be checked.
+	 */
+	feature_prepare_for_sleep();
+
+	/* Call low-level ASM sleep handler */
+	low_sleep_handler();
 
+	/* Restore things */
+	feature_wake_up();
+
+	// Don't restore PCI for now, it crashes. Maybe unnecessary on pbook
+	// pbook_pci_restore();
+
+	restore_via_state();
+		
 	/* Restore L2 cache */
 	if (save_l2cr)
- 		_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+ 		_set_L2CR(save_l2cr);
+	
+	/* Restore userland MMU context */
+	set_context(current->mm->context);
 
-	/* reenable interrupts */
-	sleep_restore_intrs();
+	/* Re-enable DEC interrupts and kick DEC */
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+	sti();
+	asm volatile("mtdec %0" : : "r" (0x10000000));
+	
+	/* Tell PMU we are ready */
+	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+	while (!req.complete)
+		pmu_poll();
+	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+	while (!req.complete)
+		pmu_poll();
+		
+	/* ack all pending interrupts */
+	timeout = 100000;
+	interrupt_data[0] = 1;
+	while (interrupt_data[0] || pmu_state != idle) {
+		if (--timeout < 0)
+			break;
+		if (pmu_state == idle)
+			adb_int_pending = 1;
+		via_pmu_interrupt(0, 0, 0);
+		udelay(10);
+	}
+
+	/* reenable interrupt controller */
+	openpic_sleep_restore_intrs();
+
+	/* Leave some time for HW to settle down */
+	mdelay(100);
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -1320,6 +1598,8 @@
 	return 0;
 }
 
+#endif
+
 #define PB3400_MEM_CTRL		((unsigned int *)0xf8000070)
 
 int __openfirmware powerbook_sleep_3400(void)
@@ -1328,7 +1608,7 @@
 	unsigned long msr;
 	unsigned int hid0;
 	unsigned long p, wait;
-	struct adb_request sleep_req;
+	struct adb_request req;
 
 	/* Notify device drivers */
 	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
@@ -1356,8 +1636,12 @@
 	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
 		mb();
 
+	/* Wait for completion of async backlight requests */
+	while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+		pmu_poll();
+
 	/* Disable all interrupts except pmu */
-	sleep_save_intrs(vias->intrs[0].line);
+	pmac_sleep_save_intrs(vias->intrs[0].line);
 
 	/* Make sure the decrementer won't interrupt us */
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
@@ -1377,8 +1661,8 @@
 	}
 
 	/* Ask the PMU to put us to sleep */
-	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
-	while (!sleep_req.complete)
+	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+	while (!req.complete)
 		mb();
 
 	/* displacement-flush the L2 cache - necessary? */
@@ -1387,9 +1671,9 @@
 	asleep = 1;
 
 	/* Put the CPU into sleep mode */
-	asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+	hid0 = _get_HID0();
 	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
-	asm volatile("mtspr 1008,%0" : : "r" (hid0));
+	_set_HID0(hid0);
 	save_flags(msr);
 	msr |= MSR_POW | MSR_EE;
 	restore_flags(msr);
@@ -1404,7 +1688,7 @@
 		mb();
 
 	/* reenable interrupts */
-	sleep_restore_intrs();
+	pmac_sleep_restore_intrs();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -1576,20 +1860,24 @@
 		case PMU_PADDINGTON_BASED:
 			error = powerbook_sleep_G3();
 			break;
+#ifdef PMU_CORE99_SLEEP
+		case PMU_KEYLARGO_BASED:
+			error = powerbook_sleep_Core99();
+			break;
+#endif			
 		default:
 			error = -ENOSYS;
 		}
 		return error;
 	case PMU_IOC_GET_BACKLIGHT:
-		if (!pmu_has_backlight)
-			return -ENOSYS;
-		return put_user(backlight_level, (__u32 *)arg);
+		error = get_backlight_level();
+		if (error < 0)
+			return error;
+		return put_user(error, (__u32 *)arg);
 	case PMU_IOC_SET_BACKLIGHT:
-		if (!pmu_has_backlight)
-			return -ENOSYS;
 		error = get_user(value, (__u32 *)arg);
 		if (!error)
-			pmu_set_brightness(value);
+			error = set_backlight_level(value);
 		return error;
 	case PMU_IOC_GET_MODEL:
 	    	return put_user(pmu_kind, (__u32 *)arg);
@@ -1623,7 +1911,7 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
-#if 0
+#ifdef DEBUG_SLEEP
 static inline void polled_handshake(volatile unsigned char *via)
 {
 	via[B] &= ~TREQ; eieio();
@@ -1689,4 +1977,4 @@
 	restore_flags(flags);
 	return 0;
 }
-#endif /* 0 */
+#endif /* DEBUG_SLEEP */
diff -urN linux-2.2.18-pre20/drivers/net/bmac.c linux/drivers/net/bmac.c
--- linux-2.2.18-pre20/drivers/net/bmac.c	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/bmac.c	Mon Dec  3 22:14:16 2001
@@ -248,12 +248,16 @@
 	dbdma_reset(rd);
 	dbdma_reset(td);
 
+	dbdma_st32((volatile unsigned long *)&rd->intr_sel, 0x40);
+	dbdma_st32((volatile unsigned long *)&rd->br_sel, 0x40);
+	dbdma_st32((volatile unsigned long *)&td->wait_sel, 0x20);
+
 	feature_set(bp->node, FEATURE_BMac_IO_enable);
-	udelay(10000);
+	mdelay(100);
 	feature_set(bp->node, FEATURE_BMac_reset);
-	udelay(10000);
+	mdelay(10);
 	feature_clear(bp->node, FEATURE_BMac_reset);
-	udelay(10000);
+	mdelay(10);
 }
 
 #define MIFDELAY	udelay(10)
diff -urN linux-2.2.18-pre20/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- linux-2.2.18-pre20/drivers/net/de4x5.c	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/de4x5.c	Mon Dec  3 22:14:16 2001
@@ -4165,7 +4165,7 @@
     /* If possible, try to fix a broken card - SMC only so far */
     srom_repair(dev, broken);
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_POWERMAC
     /* 
     ** If the address starts with 00 a0, we have to bit-reverse
     ** each byte of the address.
@@ -4178,7 +4178,7 @@
 	    dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
 	}
     }
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_POWERMAC */
 
     /* Test for a bad enet address */
     status = test_bad_enet(dev, status);
diff -urN linux-2.2.18-pre20/drivers/net/gmac.c linux/drivers/net/gmac.c
--- linux-2.2.18-pre20/drivers/net/gmac.c	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/gmac.c	Mon Dec  3 22:14:16 2001
@@ -6,6 +6,13 @@
  * 
  * portions based on sunhme.c by David S. Miller
  *
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/06/2000
+ * - check init_etherdev return in gmac_probe1
+ * BenH <bh40@calva.net> - 03/09/2000
+ * - Add support for new PHYs
+ * - Add some PowerBook sleep code
+ * 
  */
 
 #include <linux/module.h>
@@ -21,18 +28,25 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/timer.h>
+#include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/bitops.h>
+#include <asm/feature.h>
+#include <asm/keylargo.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#include <asm/irq.h>
+#endif
 
 #include "gmac.h"
 
 #define DEBUG_PHY
 
-/* Driver version 1.1, kernel 2.2.x */
-#define GMAC_VERSION	"v1.1k2"
+/* Driver version 1.3, kernel 2.2.x */
+#define GMAC_VERSION	"v1.3k2"
 
 static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN];
 static struct device *gmacs = NULL;
@@ -45,9 +59,12 @@
 static void mii_interrupt(struct gmac *gm);
 static int mii_lookup_and_reset(struct gmac *gm);
 static void mii_setup_phy(struct gmac *gm);
+static int mii_do_reset_phy(struct gmac *gm, int phy_addr);
+static void mii_init_BCM5400(struct gmac *gm);
 
 static void gmac_set_power(struct gmac *gm, int power_up);
 static int gmac_powerup_and_reset(struct device *dev);
+static void gmac_set_gigabit_mode(struct gmac *gm, int gigabit);
 static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex);
 static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
 static void gmac_init_rings(struct gmac *gm, int from_irq);
@@ -67,6 +84,13 @@
 extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
 		   unsigned char *devfn_ptr);
 
+#ifdef CONFIG_PMAC_PBOOK
+int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier gmac_sleep_notifier = {
+	gmac_sleep_notify, SLEEP_LEVEL_NET,
+};
+#endif
+
 /* Stuff for talking to the physical-layer chip */
 static int
 mii_read(struct gmac *gm, int phy, int r)
@@ -136,6 +160,18 @@
 	udelay(GM_MIF_POLL_DELAY);
 }
 
+/* Link modes of the BCM5400 PHY */
+static int phy_BCM5400_link_table[8][3] = {
+	{ 0, 0, 0 },	/* No link */
+	{ 0, 0, 0 },	/* 10BT Half Duplex */
+	{ 1, 0, 0 },	/* 10BT Full Duplex */
+	{ 0, 1, 0 },	/* 100BT Half Duplex */
+	{ 0, 1, 0 },	/* 100BT Half Duplex */
+	{ 1, 1, 0 },	/* 100BT Full Duplex*/
+	{ 1, 0, 1 },	/* 1000BT */
+	{ 1, 0, 1 },	/* 1000BT */
+};
+
 static void
 mii_interrupt(struct gmac *gm)
 {
@@ -150,8 +186,9 @@
 	/* We read the Auxilliary Status Summary register */
 	phy_status = mii_read(gm, gm->phy_addr, MII_SR);
 	if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) {
-		int		full_duplex;
-		int		link_100;
+		int		full_duplex = 0;
+		int		link_100 = 0;
+		int		gigabit = 0;
 #ifdef DEBUG_PHY
 		printk("Link state change, phy_status: 0x%04x\n", phy_status);
 #endif
@@ -163,8 +200,9 @@
 		else
 			GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN);
 
-		/* Link ? For now we handle only the 5201 PHY */
+		/* Link ? Check for speed and duplex */
 		if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) {
+		    int restart = 0;
 		    if (gm->phy_type == PHY_B5201) {
 		    	int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
 #ifdef DEBUG_PHY
@@ -172,19 +210,41 @@
 #endif
 		    	full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
 		    	link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
-		    } else {
-		    	full_duplex = 1;
-		    	link_100 = 1;
+		    } else if (gm->phy_type == PHY_B5400) {
+		    	int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS);
+		    	int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+		    			MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
+#ifdef DEBUG_PHY
+			printk("    Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n",
+				aux_stat, link);
+#endif
+		    	full_duplex = phy_BCM5400_link_table[link][0];
+		    	link_100 = phy_BCM5400_link_table[link][1];
+		    	gigabit = phy_BCM5400_link_table[link][2];
+		    } else if (gm->phy_type == PHY_LXT971) {
+		    	int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
+#ifdef DEBUG_PHY
+			printk("    Link up ! LXT971 stat2: 0x%04x\n", stat2);
+#endif
+		    	full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
+		    	link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0);
 		    }
 #ifdef DEBUG_PHY
 		    printk("    full_duplex: %d, speed: %s\n", full_duplex,
-		    	link_100 ? "100" : "10");
+		    	gigabit ? "1000" : (link_100 ? "100" : "10"));
 #endif
+                    if (gigabit != gm->gigabit) {
+                    	gm->gigabit = gigabit;
+                    	gmac_set_gigabit_mode(gm, gm->gigabit);
+                    	restart = 1;
+                    }
 		    if (full_duplex != gm->full_duplex) {
 			gm->full_duplex = full_duplex;
 			gmac_set_duplex_mode(gm, gm->full_duplex);
-			gmac_start_dma(gm);
+			restart = 1;
 		    }
+		    if (restart)
+			gmac_start_dma(gm);
 		} else if (!(phy_status & MII_SR_LKS)) {
 #ifdef DEBUG_PHY
 		    printk("    Link down !\n");
@@ -194,16 +254,73 @@
 }
 
 static int
+mii_do_reset_phy(struct gmac *gm, int phy_addr)
+{
+	int mii_control, timeout;
+	
+	mii_control = mii_read(gm, phy_addr, MII_CR);
+	mii_write(gm, phy_addr, MII_CR, mii_control | MII_CR_RST);
+	mdelay(10);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mii_control = mii_read(gm, phy_addr, MII_CR);
+		if (mii_control == -1) {
+			printk(KERN_ERR "%s PHY died after reset !\n",
+				gm->dev->name);
+			return 1;
+		}
+		if ((mii_control & MII_CR_RST) == 0)
+			break;
+		mdelay(10);
+	}
+	if (mii_control & MII_CR_RST) {
+		printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name);
+		return 1;
+	}
+	mii_write(gm, phy_addr, MII_CR, mii_control & ~MII_CR_ISOL);
+	return 0;
+}
+
+static void
+mii_init_BCM5400(struct gmac *gm)
+{
+	int data;
+
+	data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL);
+	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+	mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data);
+	
+	data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
+	
+	mdelay(10);
+	mii_do_reset_phy(gm, 0x1f);
+	
+	data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data);
+
+	data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL);
+	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+	mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data);
+}
+
+static int
 mii_lookup_and_reset(struct gmac *gm)
 {
-	int	i, timeout;
-	int	mii_status, mii_control;
+	int	i, mii_status, mii_control;
 
-	/* Find the PHY */
 	gm->phy_addr = -1;
 	gm->phy_type = PHY_UNKNOWN;
+
+	/* Hard reset the PHY */
+	feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT);
+	mdelay(10);
+	feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE);
+	mdelay(10);
 	
-	for(i=31; i>0; --i) {
+	/* Find the PHY */
+	for(i=0; i<32; i++) {
 		mii_control = mii_read(gm, i, MII_CR);
 		mii_status = mii_read(gm, i, MII_SR);
 		if (mii_control != -1  && mii_status != -1 &&
@@ -211,29 +328,13 @@
 			break;
 	}
 	gm->phy_addr = i;
-	if (gm->phy_addr < 0)
+	if (gm->phy_addr > 31)
 		return 0;
 
 	/* Reset it */
-	mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST);
-	mdelay(10);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mii_read(gm, gm->phy_addr, MII_CR);
-		if (mii_control == -1) {
-			printk(KERN_ERR "%s PHY died after reset !\n",
-				gm->dev->name);
-			goto fail;
-		}
-		if ((mii_control & MII_CR_RST) == 0)
-			break;
-		mdelay(10);
-	}
-	if (mii_control & MII_CR_RST) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name);
+	if (mii_do_reset_phy(gm, gm->phy_addr))
 		goto fail;
-	}
-	mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL);
-
+	
 	/* Read the PHY ID */
 	gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |
 		mii_read(gm, gm->phy_addr, MII_ID1);
@@ -242,10 +343,15 @@
 #endif
 	if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {
 		gm->phy_type = PHY_B5400;
-		printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n",
+		printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n",
 			gm->dev->name);
+		mii_init_BCM5400(gm);		
 	} else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {
 		gm->phy_type = PHY_B5201;
+		printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name);
+	} else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) {
+		gm->phy_type = PHY_LXT971;
+		printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name);
 	} else {
 		printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n",
 			gm->dev->name, gm->phy_id);
@@ -288,9 +394,7 @@
 gmac_set_power(struct gmac *gm, int power_up)
 {
 	if (power_up) {
-		out_le32(gm->sysregs + 0x20/4,
-			in_le32(gm->sysregs + 0x20/4) | 0x02000000);
-		udelay(20);
+		feature_set_gmac_power(gm->of_node, 1);
 		if (gm->pci_devfn != 0xff) {
 			u16 cmd;
 			
@@ -308,9 +412,7 @@
 	} else {
 		/* FIXME: Add PHY power down */
 		gm->phy_type = 0;
-		out_le32(gm->sysregs + 0x20/4,
-			in_le32(gm->sysregs + 0x20/4) & ~0x02000000);
-		udelay(20);
+		feature_set_gmac_power(gm->of_node, 0);
 	}
 }
 
@@ -357,6 +459,22 @@
 	}
 }
 
+/* Set the MAC gigabit mode. Side effect: stops Tx MAC */
+static void
+gmac_set_gigabit_mode(struct gmac *gm, int gigabit)
+{
+	/* Stop Tx MAC */
+	GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+	while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE)
+		;
+	
+	if (gigabit) {
+		GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE);
+	} else {
+		GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE);
+	}
+}
+
 static void
 gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
 {
@@ -388,12 +506,12 @@
 		(31 << GM_GCONF_TXDMA_LIMIT_SHIFT) |
 		(31 << GM_GCONF_RXDMA_LIMIT_SHIFT));
 	GM_OUT(GM_TX_CONF,
-		GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT |
+		(GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT) |
 		NTX_CONF);
-/* 34 byte offset for checksum computation.  This works because ip_input() will clear out
- * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
- * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr)
- */
+	/* 34 byte offset for checksum computation.  This works because ip_input() will clear out
+	 * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
+	 * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr)
+	 */
 	GM_OUT(GM_RX_CONF,
 		(RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) |
 		(0x22 << GM_RX_CONF_CHK_START_SHIFT) |
@@ -703,6 +821,65 @@
 	return 0;
 }
 
+#ifdef CONFIG_PMAC_PBOOK
+int
+gmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	struct gmac *gm;
+	int i;
+	
+	/* XXX should handle more than one */
+	if (gmacs == NULL)
+		return PBOOK_SLEEP_OK;
+
+	gm = (struct gmac *) gmacs->priv;
+	if (!gm->opened)
+		return PBOOK_SLEEP_OK;
+		
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		disable_irq(gm->dev->irq);
+		gm->dev->tbusy = 1;
+		gmac_stop_dma(gm);
+		mii_poll_stop(gm);
+		gmac_set_power(gm, 0);
+		for (i = 0; i < NRX; ++i) {
+			if (gm->rx_buff[i] != 0) {
+				dev_kfree_skb(gm->rx_buff[i]);
+				gm->rx_buff[i] = 0;
+			}
+		}
+		for (i = 0; i < NTX; ++i) {
+			if (gm->tx_buff[i] != 0) {
+				dev_kfree_skb(gm->tx_buff[i]);
+				gm->tx_buff[i] = 0;
+			}
+		}
+		break;
+	case PBOOK_WAKE:
+		/* see if this is enough */
+		gmac_powerup_and_reset(gm->dev);
+		gm->full_duplex = 0;
+		gm->phy_status = 0;
+		mii_lookup_and_reset(gm);
+		mii_setup_phy(gm);
+		gmac_init_rings(gm, 0);
+		gmac_mac_init(gm, gm->dev->dev_addr);
+		gmac_set_multicast(gm->dev);
+		mii_interrupt(gm);
+		gmac_start_dma(gm);
+		gm->dev->tbusy = 0;
+		enable_irq(gm->dev->irq);
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
 /*
  * Handle a transmit timeout
  */
@@ -712,12 +889,11 @@
 	struct gmac *gm = (struct gmac *) dev->priv;
 	int i, timeout;
 	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 	
 	printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 
+	spin_lock_irqsave(&gm->lock, flags);
+
 	/*
 	 * Do something useful here
 	 * 
@@ -758,7 +934,7 @@
 	/* Restart chip */
 	gmac_start_dma(gm);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&gm->lock, flags);
 	
 	dev->tbusy = 0;
 }
@@ -770,6 +946,7 @@
 	struct gmac *gm = (struct gmac *) dev->priv;
 	volatile struct gmac_dma_desc *dp;
 	int i;
+	unsigned long flags;
 
 	/* Check tbusy bit and handle eventual transmitter timeout */
 	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
@@ -780,9 +957,12 @@
 		return 1;
 	}
 
+	spin_lock_irqsave(&gm->lock, flags);
+
 	i = gm->next_tx;
 	if (gm->tx_buff[i] != 0) {
 		/* buffer is full, can't send this packet at the moment */
+		spin_unlock_irqrestore(&gm->lock, flags);
 		return 1;
 	}
 	gm->next_tx = (i + 1) & (NTX - 1);
@@ -804,6 +984,8 @@
 
 	dev->tbusy = (gm->tx_buff[gm->next_tx] != 0);
 
+	spin_unlock_irqrestore(&gm->lock, flags);
+
 	return 0;
 }
 
@@ -820,9 +1002,8 @@
 	int gone, i;
 
 	i = gm->tx_gone;
-	gone = GM_IN(GM_TX_COMP);
-	
-	while (force_cleanup || i != gone) {
+	do {
+		gone = GM_IN(GM_TX_COMP);
 		skb = gm->tx_buff[i];
 		if (skb == NULL)
 			break;
@@ -837,7 +1018,7 @@
 		dev_kfree_skb(skb);
 		if (++i >= NTX)
 			i = 0;
-	}
+	} while (force_cleanup || i != gone);
 	gm->tx_gone = i;
 
 	if (!force_cleanup && dev->tbusy &&
@@ -987,15 +1168,23 @@
 	}
 	
 	if (status & GM_IRQ_MIF) {
+		spin_lock(&gm->lock);
 		mii_interrupt(gm);
+		spin_unlock(&gm->lock);
 	}
 
-	if (status & GM_IRQ_RX_DONE)
+	if (status & GM_IRQ_RX_DONE) {
+		spin_lock(&gm->lock);
 		gmac_receive(dev);
-
-	if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL))
+		spin_unlock(&gm->lock);
+	}
+	
+	if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) {
+		spin_lock(&gm->lock);
 		gmac_tx_cleanup(dev, 0);
-
+		spin_unlock(&gm->lock);
+	}
+	
 	dev->interrupt = 0;
 }
 
@@ -1076,10 +1265,12 @@
 	dev->base_addr = gmac->addrs[0].address;
 	gm->regs = (volatile unsigned int *)
 		ioremap(gmac->addrs[0].address, 0x10000);
-	gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
 	dev->irq = gmac->intrs[0].line;
 	gm->dev = dev;
-
+	gm->of_node = gmac;
+	
+	spin_lock_init(&gm->lock);
+	
 	if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) {
 		gm->pci_bus = gm->pci_devfn = 0xff;
 		printk(KERN_ERR "Can't locate GMAC PCI entry\n");
@@ -1117,6 +1308,9 @@
 
 	gmacs = dev;
 
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&gmac_sleep_notifier);
+#endif
 	return 0;
 }
 
diff -urN linux-2.2.18-pre20/drivers/net/gmac.h linux/drivers/net/gmac.h
--- linux-2.2.18-pre20/drivers/net/gmac.h	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/gmac.h	Mon Dec  3 22:14:16 2001
@@ -730,8 +730,9 @@
  */
 
 /* Supported PHYs (phy_type field ) */
-#define PHY_B5400	5400
-#define PHY_B5201	5201
+#define PHY_B5400	0x5400
+#define PHY_B5201	0x5201
+#define PHY_LXT971	0x0971
 #define PHY_UNKNOWN	0
 
 /* Identification (for multi-PHY) */
@@ -745,6 +746,11 @@
 #define MII_BCM5400_REV                         0x01
 #define MII_BCM5400_ID                          ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4))
 #define MII_BCM5400_MASK                        0xfffffff0
+#define MII_LXT971_OUI                          0x0004de
+#define MII_LXT971_MODEL                        0x0e
+#define MII_LXT971_REV                          0x00
+#define MII_LXT971_ID                           ((MII_LXT971_OUI << 10) | (MII_LXT971_MODEL << 4))
+#define MII_LXT971_MASK                         0xfffffff0
 
 /* BCM5201 AUX STATUS register */
 #define MII_BCM5201_AUXCTLSTATUS		0x18
@@ -764,6 +770,26 @@
 #define MII_BCM5201_MULTIPHY_SERIALMODE         0x0002
 #define MII_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
 
+/* MII BCM5400 1000-BASET Control register */
+#define MII_BCM5400_GB_CONTROL			0x09
+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
+
+/* MII BCM5400 AUXCONTROL register */
+#define MII_BCM5400_AUXCONTROL                  0x18
+#define MII_BCM5400_AUXCONTROL_PWR10BASET       0x0004
+
+/* MII BCM5400 AUXSTATUS register */
+#define MII_BCM5400_AUXSTATUS                   0x19
+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
+
+/* MII LXT971 STATUS2 register */
+#define MII_LXT971_STATUS2			0x11
+#define MII_LXT971_STATUS2_SPEED		0x4000
+#define MII_LXT971_STATUS2_LINK			0x0400
+#define MII_LXT971_STATUS2_FULLDUPLEX		0x0200
+#define MII_LXT971_STATUS2_AUTONEG_COMPLETE	0x0080
+
 
 
 	/*
@@ -829,8 +855,8 @@
 	 
 struct gmac {
 	volatile unsigned int		*regs;	/* hardware registers, virtual addr */
-	volatile unsigned int		*sysregs;
 	struct device			*dev;
+	struct device_node		*of_node;
 	unsigned long			tx_desc_page;	/* page for DMA descriptors */
 	unsigned long			rx_desc_page;	/* page for DMA descriptors */
 	volatile struct			gmac_dma_desc *rxring;
@@ -845,9 +871,11 @@
 	int				phy_type;
 	int				phy_status;	/* Cached PHY status */
 	int				full_duplex;	/* Current set to full duplex */
+	int				gigabit;	/* Current set to 1000BT */
 	struct net_device_stats		stats;
 	u8				pci_bus;
 	u8				pci_devfn;
+	spinlock_t			lock;
 	int				opened;
 };
 
diff -urN linux-2.2.18-pre20/drivers/net/hdlc.c linux/drivers/net/hdlc.c
--- linux-2.2.18-pre20/drivers/net/hdlc.c	Mon Sep  4 10:39:19 2000
+++ linux/drivers/net/hdlc.c	Mon Dec  3 22:14:16 2001
@@ -50,6 +50,7 @@
 #define CISCO_ADDR_REQ          0       /* Cisco address request */
 #define CISCO_ADDR_REPLY        1       /* Cisco address reply */
 #define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
+#define CISCO_SYS_INFO		0x2000	/* Cisco interface/system info */
 
 static int hdlc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 
@@ -141,6 +142,11 @@
 		return;
 #endif
 
+	case CISCO_SYS_INFO:
+		/* Packet is not needed, drop it. */
+		dev_kfree_skb(skb);
+		return;
+
 	case CISCO_KEEPALIVE:
 		if (skb->len != CISCO_PACKET_LEN && 
 		    skb->len != CISCO_BIG_PACKET_LEN) {
@@ -206,7 +212,7 @@
 		} /* switch(keepalive type) */
 	} /* switch(protocol) */
 
-	printk(KERN_INFO "%s: Unusupported protocol %x\n", hdlc->name,
+	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc->name,
 	       data->protocol);
 	hdlc->stats.rx_bytes+=skb->len;
 	hdlc->stats.rx_packets++;
diff -urN linux-2.2.18-pre20/drivers/s390/Config.in linux/drivers/s390/Config.in
--- linux-2.2.18-pre20/drivers/s390/Config.in	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/Config.in	Mon Dec  3 22:14:17 2001
@@ -52,7 +52,7 @@
   bool 'Network device support' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     comment 'S390 Network devices'
-    bool 'CTC device support' CONFIG_CTC
+    tristate 'CTC device support' CONFIG_CTC
     bool 'IUCV device support (VM only)' CONFIG_IUCV
     tristate 'Dummy net driver support' CONFIG_DUMMY
     bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
diff -urN linux-2.2.18-pre20/drivers/s390/Makefile linux/drivers/s390/Makefile
--- linux-2.2.18-pre20/drivers/s390/Makefile	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/Makefile	Mon Dec  3 22:14:17 2001
@@ -11,18 +11,17 @@
 
 CFLAGS += 
 O_TARGET := io.o
-O_OBJS   := ccwcache.o
+O_OBJS   := ccwcache.o idals.o
 M_OBJS   :=
 
 SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
 	arch/s390/drivers/misc  arch/s390/drivers/net
 MOD_SUB_DIRS += ./net ./block
 
-O_OBJS := block/s390-block.o \
+O_OBJS += block/s390-block.o \
   char/s390-char.o \
   misc/s390-misc.o \
-  net/s390-net.o \
-  ccwcache.o
+  net/s390-net.o 
 
 io.o: $(O_OBJS)
 
@@ -37,6 +36,5 @@
 
 net/s390-net.o: dummy
 	$(MAKE) -C net
-
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.18-pre20/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile
--- linux-2.2.18-pre20/drivers/s390/block/Makefile	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/Makefile	Mon Dec  3 22:14:17 2001
@@ -2,7 +2,7 @@
 
 CFLAGS += 
 O_TARGET := s390-block.o
-O_OBJS   :=         
+O_OBJS   := 
 M_OBJS   :=
 D_OBJS   :=
 
diff -urN linux-2.2.18-pre20/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- linux-2.2.18-pre20/drivers/s390/block/dasd.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/dasd.c	Mon Dec  3 22:14:17 2001
@@ -11,7 +11,7 @@
             Adapted request function to make it work on 2.4
  * 07/10/00 Added some code to the request function to dequeue requests
             that cannot be handled due to errors
- * 07/10/00 Moved linux/ccwcache.h to asm/
+ * 07/10/00 Moved linux/dasd.h and linux/ccwcache.h to asm/
  * 07/10/00 Fixed a bug when formatting a 'new' device       
  * 07/10/00 Removed an annoying message from dasd_format 
  * 07/11/00 Reanimated probeonly mode    
@@ -20,9 +20,25 @@
  * 07/12/00 fixed a bug in dasd_devices_open when having 'unknown' devices
  * 07/13/00 fixed error message when having no device
  * 07/13/00 added code for dynamic device recognition
+ * 07/14/00 reorganized the format process for better ERP
+ * 07/17/00 fixed a race condition when sleeping on a request
+ * 07/17/00 modified default ERP action to use TIC instead of NOP
+ * 07/20/00 fixed proc filesystem for 2.4
+ * 07/24/00 fixed missing interrupt handler
+ * 08/01/00 fixed a race condition when sleeping on a request 
+ * 09/15/00 fixed a race condition on dasd_do_chanq
+ * 09/15/00 got rid of some paranoia
+ * 09/18/00 fixed the state machine for duplicate devnos in dasd ranges
+ * 10/26/00 fixed ITPM PL020141RSC load module to a kernel with static driver 
+            are the fixes in dasd_init
+ * 10/26/00 fixed ITPM PL020062RSC formatting r/o volume 
+            are the fixes in dasd_format
+ * 10/26/00 fixed ITPM PL010261EPA race condition when formatting  
+            are the fixes in dasd_do_chanq
  */
 
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/stddef.h>
@@ -34,6 +50,12 @@
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/ctype.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/spinlock.h>                      
+#else 
+#include <asm/spinlock.h>
+#endif     
+
 #include <asm/ccwcache.h>
 #include <asm/dasd.h>
 #include <linux/blk.h>
@@ -49,15 +71,15 @@
 #include <asm/atomic.h>
 #include <asm/delay.h>
 #include <asm/io.h>
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#include <asm/spinlock.h>
-#endif /* LINUX_IS_24 */
 #include <asm/semaphore.h>
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/s390dyn.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))      
+#include <asm/idals.h>
+#endif /* LINUX_IS_24 */                               
 
 #include "dasd.h"
 #ifdef CONFIG_DASD_ECKD
@@ -73,7 +95,7 @@
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct block_device_operations dasd_device_operations;
 #endif /* VERSION_CODE */
-
+  
 #ifdef MODULE
 #define EXPORT_SYMTAB
 #include <linux/module.h>
@@ -113,7 +135,6 @@
 static void dasd_do_chanq (void);
 static void schedule_request_fn (void (*func) (void));
 static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
-static int dasd_oper_handler ( int irq, devreg_t *devreg );
 
 /* SECTION: managing setup of dasd_driver */
 typedef struct dasd_range_t {
@@ -145,7 +166,7 @@
         }
         return r;
 }
-
+ 
 static void
 dasd_add_range (int from, int to)
 {
@@ -162,7 +183,7 @@
         }  else {
                 range -> to = to;
         }
-
+        
         /* chain current range to end of list */
         if ( dasd_range_head == NULL ) {
                 dasd_range_head = range;
@@ -226,7 +247,7 @@
                 count ++;
                 tmp = end;
         } while ( tmp != NULL && *tmp != '\0' );
-	}
+}
 
 static char dasd_parm_string[1024] = {0,};
 
@@ -239,12 +260,12 @@
                 *(dasd_parm_string+strlen(dasd_parm_string))=',';
         }  else {
                 first_time = 0;
-	}
+        }
         memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1);
         return 1;
 }
 #else
-void
+void 
 dasd_setup (char *str, int *ints) 
 {
         static int first_time = 1;
@@ -269,7 +290,7 @@
 {
 	char *temp;
 	int from, to;
-
+        
       	if ( *str ) { 
         dasd_probeonly = 0;
 	}
@@ -284,19 +305,19 @@
                 } else if ( strncmp ( *str,"probeonly",strlen("probeonly"))== 0) {
                         dasd_probeonly = 1;
                         printk (KERN_INFO "turning to probeonly mode\n");
-			break;
+                        break;
                 } else {
                         dasd_autodetect = 0;
                         from = dasd_strtoul (temp, &temp);          
                         if (*temp == '-') {
                                 temp++;
                                 to = dasd_strtoul (temp, &temp);
-		}
+                        }
                         dasd_add_range (from, to);
-		}
+                }
                 str ++;
-		}
-		}
+        }
+}
 
 int
 devindex_from_devno (int devno)
@@ -310,11 +331,11 @@
 			devindex += devno - temp -> from;
 			break;
 		}
-		}
+	}
         if ( temp == NULL ) 
                 return -ENODEV;
 	return devindex;
-		}
+}
 
 /* SECTION: ALl needed for multiple major numbers */
 
@@ -335,7 +356,7 @@
 #endif /* LINUX_IS_24 */
 			nr_real:DASD_PER_MAJOR,
 		}
-		}
+	}
 #if 0
         ,
 	{
@@ -352,8 +373,8 @@
 			max_nr:DASD_PER_MAJOR,
 #endif /* LINUX_IS_24 */
 			nr_real:DASD_PER_MAJOR,
-			}
 		}
+	}
 #endif
 };
 
@@ -361,7 +382,7 @@
 find_dasd_device (int devindex)
 {
 	major_info_t *major_info = dasd_major_info;
-	while (major_info && devindex > DASD_PER_MAJOR) {
+	while (major_info && devindex >= DASD_PER_MAJOR) {
 		devindex -= DASD_PER_MAJOR;
 		major_info = major_info->next;
 	}
@@ -374,12 +395,12 @@
 major_info_from_devindex (int devindex)
 {
 	major_info_t *major_info = dasd_major_info;
-	while (major_info && devindex > DASD_PER_MAJOR) {
+	while (major_info && devindex >= DASD_PER_MAJOR) {
 		devindex -= DASD_PER_MAJOR;
 		major_info = major_info->next;
 	}
 	return major_info;
-	}
+}
 
 int
 major_from_devindex (int devindex)
@@ -413,7 +434,7 @@
  * void dasd_discipline_enq (dasd_discipline_t * d)
  */
 
-void 
+void
 dasd_discipline_enq (dasd_discipline_t * d)
 {
 	spin_lock (&discipline_lock);
@@ -473,14 +494,14 @@
 
 static void
 dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
-	{
+{
 	cqr->next = q->head;
 	q->head = cqr;
 	if (q->tail == NULL)
 		q->tail = cqr;
 	q->queued_requests++;
 	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
-	}
+}
 
 /* 
  * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
@@ -507,7 +528,7 @@
 		if (prev->next == NULL)
 			q->tail = prev;
 	}
-	cqr->next = NULL;
+/*	cqr->next = NULL; */
 	q->queued_requests--;
 	return 0;
 }
@@ -520,6 +541,8 @@
 #else
 static spinlock_t cq_lock = SPIN_LOCK_UNLOCKED;		/* spinlock for cq_head */
 #endif /* LINUX_IS_24 */
+#else
+int cq_lock;
 #endif				/* __SMP__ */
 static dasd_chanq_t *qlist_head = NULL;		/* head of queue of queues */
 
@@ -532,18 +555,19 @@
 static void
 qlist_enq (dasd_chanq_t * q)
 {
+	long flags;
 	if (q == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER " NULL queue to be queued to queue of queues\n");
 		return;
 	}
-	spin_lock (&cq_lock);
+	spin_lock_irqsave (&cq_lock,flags);
 	if (atomic_read (&q->flags) & DASD_CHANQ_ACTIVE) {
 		printk (KERN_WARNING PRINTK_HEADER " Queue already active");
 	}
 	atomic_set_mask (DASD_CHANQ_ACTIVE, &q->flags);
 	q->next_q = qlist_head;
 	qlist_head = q;
-	spin_unlock (&cq_lock);
+	spin_unlock_irqrestore (&cq_lock,flags);
 }
 
 /* 
@@ -555,8 +579,8 @@
 static void
 qlist_deq (dasd_chanq_t * q)
 {
-
-	if (qlist_head == NULL) {
+	long flags;
+	if (qlist_head == NULL) {	
 		printk (KERN_ERR PRINTK_HEADER "Channel queue is empty%s\n", "");
 		return;
 	}
@@ -564,7 +588,7 @@
 		printk (KERN_WARNING PRINTK_HEADER " NULL queue to be dequeued from queue of queues\n");
 		return;
 	}
-	spin_lock (&cq_lock);
+	spin_lock_irqsave (&cq_lock,flags);
 	if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
 		printk (KERN_WARNING PRINTK_HEADER " Queue not active\n");
 	} else if (qlist_head == q) {
@@ -580,7 +604,7 @@
 	}
 	atomic_clear_mask (DASD_CHANQ_ACTIVE, &q->flags);
 	q->next_q = NULL;
-	spin_unlock (&cq_lock);
+	spin_unlock_irqrestore (&cq_lock,flags);
 }
 
 /* SECTION: All the gendisk stuff */
@@ -608,7 +632,7 @@
         resetup_one_dev(dd,minor>>DASD_PARTN_BITS);
 #endif /* LINUX_IS_24 */
 	return rc;
-	}
+}
 
 /* SECTION: Managing wrappers for ccwcache */
 
@@ -623,8 +647,8 @@
         int i;
         for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
           dasd_emergency_req[i] = (ccw_req_t*)get_free_page(GFP_KERNEL);
-		}
         }
+}
 
 static void
 dasd_cleanup_emergency_req ( void ) 
@@ -654,6 +678,7 @@
                 if ( dasd_emergency_req[i] != NULL ) {
                         rv = dasd_emergency_req[i];
                         dasd_emergency_req[i] = NULL;
+			break;
                 }
         }
         spin_unlock(&dasd_emergency_req_lock);
@@ -670,15 +695,15 @@
         return rv;
 }
 
-void
+void 
 dasd_free_request (ccw_req_t * request)
 {
         if ( request -> cache >= (kmem_cache_t *)dasd_emergency_req &&
              request -> cache <= (kmem_cache_t *)(dasd_emergency_req + DASD_EMERGENCY_REQUESTS) ) {
                 *((ccw_req_t **)(request -> cache)) = request;
-	} else {
+        } else {
                 ccw_free_request(request);
-	}
+        }
 }
 
 /* SECTION: Managing the device queues etc. */
@@ -718,7 +743,7 @@
           major_info_t *mi;
           for (mi=dasd_major_info; mi != NULL; mi = mi->next ) {
             do_dasd_request(BLK_DEFAULT_QUEUE(mi->gendisk.major));
-	}
+          }
         }
 #else
         do_dasd_request ();
@@ -754,10 +779,10 @@
 	major_info_t *major_info;
 	struct request *req;
 
-		if (!cqr) {
+	if (!cqr) {
 		printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
 		return -EINVAL;
-		}
+	}
 	irq = device->devinfo.irq;
 	devno = device->devinfo.devno;
 	req = (struct request *) cqr->req;
@@ -776,39 +801,39 @@
 		return -EINVAL;
 	}
 	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-		do {
+	do {
 		asm volatile ("STCK %0":"=m" (cqr->startclk));
 		rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
 		switch (rc) {
 		case 0:
                         if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
 				atomic_set_mask (DASD_CHANQ_BUSY, &device->queue.flags);
-			}
+                        }
                         if ( cqr->expires ) {
                                 cqr->expires += cqr->startclk;
-                                }
-                                break;
+                        }
+			break;
 		case -ENODEV:
 			printk (KERN_WARNING PRINTK_HEADER
 			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 				" appears not to be present %d retries left\n",
 				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
 				retries);
-                                break;
+			break;
 		case -EIO:
 			printk (KERN_WARNING PRINTK_HEADER
 			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 				" I/O error %d retries left\n",
 				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
 				retries);
-                                break;
+			break;
 		case -EBUSY:	/* set up timer, try later */
 			printk (KERN_WARNING PRINTK_HEADER
 			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 				" is busy %d retries left\n",
 				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
 				retries);
-				break;
+			break;
 		default:
 			printk (KERN_WARNING PRINTK_HEADER
 			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
@@ -816,26 +841,63 @@
 			  " Pls report this message to linux390@de.ibm.com\n",
 				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
 				rc, retries);
-                                break;
-                        }
+			break;
+		}
 	} while (rc && retries--);
 	if (rc) {
                 atomic_compare_and_swap_debug (&cqr->status, 
                                                CQR_STATUS_IN_IO, 
                                                CQR_STATUS_ERROR);
-                                }
+	}
 	return rc;
-                        }
+}
+
+
+static int
+sleep_on_req ( ccw_req_t * req )
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        DECLARE_WAITQUEUE (wait,current);
+#else
+        struct wait_queue wait = {current, NULL};
+#endif /* LINUX_VERSION_CODE */
+        unsigned long flags;
+        int cs;
+        int rc = 0;
+        dasd_device_t *device = (dasd_device_t *)req->device;
+        s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+        dasd_chanq_enq (&device->queue, req);
+        if (!(atomic_read (&device->queue.flags) & DASD_CHANQ_ACTIVE)) {
+                qlist_enq (&device->queue);
+        }
+        dasd_schedule_bh();
+        add_wait_queue (&device->wait_q, &wait);
+        do {
+                current->state = TASK_INTERRUPTIBLE;
+                s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+                schedule ();
+                s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                cs = atomic_read (&req->status);
+        } while ( ! (cs & CQR_STATUS_FINISHED) );
+        /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ 
+        remove_wait_queue (&device->wait_q, &wait);
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+        if  ( cs & CQR_STATUS_FAILED ) {
+                rc = -EIO;
+        }
+        return rc;
+}
+
 
 static void
 dasd_end_request (struct request *req, int uptodate)
 {
 	struct buffer_head *bh;
 	while ((bh = req->bh) != NULL) {
-		req->bh = bh->b_reqnext;
+                req->bh = bh->b_reqnext;
 		bh->b_reqnext = NULL;
 		bh->b_end_io (bh, uptodate);
-			}
+	}
 	if (!end_that_request_first (req, uptodate, DASD_NAME)) {
 #ifndef DEVICE_NO_RANDOM
 		add_blkdev_randomness (MAJOR (req->rq_dev));
@@ -871,7 +933,7 @@
 	major_info_t *major_info;
 	int devno;
         int major;
-        
+
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
         {
@@ -894,34 +956,34 @@
 #else
         for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
                 major = major_info->gendisk.major;
-	prev = NULL;
-	for (req = CURRENT; req != NULL; req = next) {
-		next = req->next;
+                prev = NULL;
+                for (req = CURRENT; req != NULL; req = next) {
+                        next = req->next;
                         if (req == &blk_dev[major].plug) { /* remove plug if applicable */
                                 req->next = NULL;
-                        if (prev) {
-                                prev->next = next;
-                        } else {
-                                CURRENT = next;
-                        }
+                                if (prev) {
+                                        prev->next = next;
+                                } else {
+                                        CURRENT = next;
+                                }
                                 continue;
-			}
+                        }
 #endif /* LINUX_IS_24 */
                         devindex = devindex_from_kdev_t(req->rq_dev);
                         if ( devindex < 0 ) {
                                 printk ( KERN_WARNING PRINTK_HEADER 
                                          "requesting I/O on nonexistent device %d -> %d\n",
                                          devindex,req->rq_dev);
-				dasd_end_request (req, 0);
+                                dasd_end_request(req,0);
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
                                 blkdev_dequeue_request (req);
 #else
                                 req->next = NULL;
                                 if (prev) {
                                         prev->next = next;
-					} else {
+                                } else {
                                         CURRENT = next;
-                        }
+                                }
 #endif /* LINUX_IS_24 */
                                 continue;
                         }
@@ -1068,43 +1130,45 @@
 	volatile int cqrstatus;
 
 	for (qp = qlist_head; qp != NULL; qp = nqp) {
+
+		device = (dasd_device_t *)((long)qp - (long)offsetof(dasd_device_t,queue));
+		irq = device->devinfo.irq;
+
+		s390irq_spin_lock_irqsave (irq, flags);
+
 		/* Get first request */
 		cqr = (ccw_req_t *) (qp->head);
 		nqp = qp->next_q;
 /* empty queue -> dequeue and proceed */
 		if (!cqr) {
 			qlist_deq (qp);
+			s390irq_spin_unlock_irqrestore(irq,flags);
 			continue;
 		}
+		s390irq_spin_unlock_irqrestore(irq,flags);
+ 
 /* process all requests on that queue */
 		do {
-			dasd_discipline_t *discipline;
+			dasd_discipline_t *discipline=device->discipline;
 			next = NULL;
-			/* Sanity check... walk through disciplines */
-			for (discipline = dasd_disciplines;
-			     discipline != NULL;
-			     discipline = discipline->next)
-				if (!strncmp ((char *) &cqr->magic, discipline->ebcname, 4))
-					break;
-			if (!discipline) {	/* 1st sanity check */
+
+			if (strncmp ((char *) &cqr->magic, discipline->ebcname, 4)) {
 				panic (PRINTK_HEADER
 				       "in dasd_do_chanq: magic no mismatch %p -> 0x%lX\n",
 				       cqr, cqr->magic);
 			}
-			device = (dasd_device_t *) (cqr->device);
-			if (discipline != device->discipline) {		/* 1st sanity check */
-				printk (KERN_WARNING PRINTK_HEADER
-					"in dasd_do_chanq: discipline mismatch %p -> 0x%lX\n",
-					cqr, cqr->magic);
-				discipline = device->discipline;
+			if ( device != cqr->device ) {
+                                panic (PRINTK_HEADER
+                                       "in dasd_do_chanq: device mismatch %p -> %p(qcr) vs. %p\n",
+                                       cqr, cqr->device,device);
 			}
-			irq = device->devinfo.irq;
 			devno = device->devinfo.devno;
 			devindex = devindex_from_devno (devno);
 
-			s390irq_spin_lock_irqsave (irq, flags);
-
+			s390irq_spin_lock_irqsave (irq, 
+                        	                   flags);
 			cqrstatus = atomic_read (&cqr->status);
+
 			switch (cqrstatus) {
 			case CQR_STATUS_QUEUED:
 				if (discipline->start_IO &&
@@ -1118,8 +1182,8 @@
 					case EBUSY:
 						if (cqr->retries--) {
 							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" retrying %d retries left\n",
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:"
+								" retrying ... %d retries left\n",
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
 							break;
 						}
@@ -1128,24 +1192,29 @@
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 								" Giving up this request!\n",
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+
+							atomic_compare_and_swap_debug (&cqr->status,
+                                                                                       CQR_STATUS_QUEUED,
+                                                                                       CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
 							break;
 						}
 					}
 				}
 				break;
 			case CQR_STATUS_IN_IO:{
-					unsigned long long now;
-					unsigned long long delta;
-
+                                        unsigned long long now;
+                                        unsigned long long delta;
+                                        
 					asm volatile ("STCK %0":"=m" (now));
 					if (cqr->expires && cqr->startclk &&
 					    cqr->expires < now) {
                                                 delta = cqr->expires - cqr->startclk;
 						printk (KERN_ERR PRINTK_HEADER
 							" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-							" I/O operation outstanding longer than %Ld usecs on req %p\n",
-							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, delta >> 12, cqr);
+							" I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n",
+							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
+							cqr->expires += delta;
+#if 0
 						if ( cqr->retries-- ) {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
@@ -1159,46 +1228,45 @@
 								" You should disable that device by issueing '@#?!'\n",		/* FIXME */
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
 							atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+							halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
 							break;
 						}
+#endif
 					}
 					break;
-				}
+                        }
 			case CQR_STATUS_ERROR:{
-					dasd_erp_action_fn_t erp_action;
-					ccw_req_t *erp_cqr = NULL;
-					if (discipline->erp_action &&
-					    ((erp_action = discipline->erp_action (cqr)) != NULL)) {
-                                                printk (KERN_WARNING PRINTK_HEADER
-                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-							" Taking error recovery action %p on req %p \n",
-							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_action,cqr);
-						erp_cqr = erp_action (cqr);
-					} else {
-						printk (KERN_WARNING PRINTK_HEADER
-							" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-                                                        " No error recovery action\n",
-							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-						atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-					}
-					if ( erp_cqr != NULL ) {
-						dasd_chanq_enq_head (qp, erp_cqr);
-						next = erp_cqr;		/* prefer execution of erp ccw */
-					}
+                                        dasd_erp_action_fn_t erp_action;
+                                        ccw_req_t *erp_cqr = NULL;
+                                        
+ 					if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+ 						atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED);
+                                                next = cqr;
+                                        } else if ( cqr -> retries--  &&
+                                             cqr -> refers == NULL &&
+                                             discipline -> erp_action != NULL &&
+                                             (erp_action = discipline->erp_action (cqr)) != NULL &&
+                                             (erp_cqr = erp_action (cqr)) != NULL ) {
+                                                dasd_chanq_enq_head (qp, erp_cqr);
+                                                next = erp_cqr;		/* prefer execution of erp ccw */
+                                        } else {
+                                                atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+                                                next = cqr;
+                                        }
 					break;
 				}
 			case CQR_STATUS_DONE:{
                                         dasd_erp_postaction_fn_t erp_postaction;
                                         next = cqr->next;
+                                        asm volatile ("STCK %0":"=m" (cqr->endclk));
 					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
-						if (discipline->erp_postaction &&
-						    ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+						if ( discipline->erp_postaction &&
+						     ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" postprocessing successful error recovery action %p\n",
+								" postprocessing successful error recovery action using %p\n",
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
 							erp_postaction (cqr, 1);
-                                                        atomic_dec (&device->queue.dirty_requests);
 						} else {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
@@ -1207,68 +1275,93 @@
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
 							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
 						}
+                                                atomic_dec (&device->queue.dirty_requests);
+                                                dasd_chanq_deq (&device->queue, cqr);
+                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
 					} else if ( cqr->req ) {
-						asm volatile ("STCK %0":"=m" (cqr->endclk));
 						dasd_end_request (cqr->req, 1);
 #ifdef DASD_PROFILE
 						dasd_profile_add (cqr);
 #endif				/* DASD_PROFILE */
-					} 
-					dasd_chanq_deq (&device->queue, cqr);
-                                        dasd_free_request(cqr);
+                                                dasd_chanq_deq (&device->queue, cqr);
+                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+					} else {
+                                                /* during format we don't have the request structure */
+                                                /* notify sleeping task about finished postprocessing */
+                                                atomic_compare_and_swap_debug (&cqr->status, 
+                                                                               CQR_STATUS_DONE, 
+                                                                               CQR_STATUS_DONE | CQR_STATUS_FINISHED); 
+                                                dasd_chanq_deq (&device->queue, cqr);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                                wake_up (&device->wait_q);
+#else
+                                                if (device->wait_q) {
+                                                  wake_up (&device->wait_q);
+                                                }
+#endif /* LINUX_IS_24 */
+                                        }
 					break;
 				}
 			case CQR_STATUS_FAILED:{
 					dasd_erp_postaction_fn_t erp_postaction;
 					next = cqr->next;
+                                        asm volatile ("STCK %0":"=m" (cqr->endclk));
 					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
-						if (discipline->erp_postaction &&
-						    ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+						if ( discipline->erp_postaction &&
+                                                     ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" postprocessing unsuccessful error recovery action %p\n",
+								" postprocessing unsuccessful error recovery action using %p\n",
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
 							erp_postaction (cqr, 0);
-                                                        atomic_dec (&device->queue.dirty_requests);
-
 						} else {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 								" No procedure to postprocess unsuccessful error recovery action"
-							 " giving up request",
+                                                                " giving up request",
 								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
 							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
 						}
+                                                atomic_dec (&device->queue.dirty_requests);
+                                                dasd_chanq_deq (&device->queue, cqr);
+                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
 					} else if (cqr->req) {
-						asm volatile ("STCK %0":"=m" (cqr->endclk));
 						dasd_end_request (cqr->req, 0);
 #ifdef DASD_PROFILE
 						dasd_profile_add (cqr);
 #endif				/* DASD_PROFILE */
+                                                dasd_chanq_deq (&device->queue, cqr);
+                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
 					} else {
-						printk (KERN_WARNING PRINTK_HEADER
-							"Internal error in " __FILE__ " on line %d."
-							" inconsistent content of ccw_req_t"
-							" refers = %p,function = %p, request = %p"
-							" Pls send this message and your System.map to"
-						     " linux390@de.ibm.com\n",
-							__LINE__, cqr->refers, cqr->function, cqr->req);
-					}
-					dasd_chanq_deq (&device->queue, cqr);
-                                        dasd_free_request(cqr);
+                                                /* during format we don't have the request structure */
+                                                /* notify sleeping task about finished postprocessing */
+                                                atomic_compare_and_swap_debug (&cqr->status, 
+                                                                               CQR_STATUS_FAILED, 
+                                                                               CQR_STATUS_FAILED | CQR_STATUS_FINISHED); 
+
+                                                dasd_chanq_deq (&device->queue, cqr);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                                wake_up (&device->wait_q);
+#else
+                                                if (device->wait_q) {
+                                                  wake_up (&device->wait_q);
+                                                }
+#endif /* LINUX_IS_24 */
+                                        } 
 					break;
 				}
+
 			default:{
 					printk (KERN_WARNING PRINTK_HEADER
 						"Internal error in " __FILE__ " on line %d."
-					  " inconsistent content of ccw_req_t"
+                                                " inconsistent content of ccw_req_t"
 						" cqrstatus = %d"
 						" Pls send this message and your System.map to"
 						" linux390@de.ibm.com\n",
 						__LINE__, cqrstatus);
+				}
 			}
-		}
-                s390irq_spin_unlock_irqrestore (irq, flags);
+			s390irq_spin_unlock_irqrestore (irq, flags);
 		} while ((cqr = next) != NULL);
 	}
 	schedule_request_fn (try_request_fn);
@@ -1286,9 +1379,9 @@
 	dasd_device_t *device;
 	int devno = -1, devindex = -1;
         
-#undef ERP_DEBUG
+#undef  ERP_DEBUG
 #ifdef ERP_DEBUG 
-        static int counter = 0; 
+        static int counter = 0;
 #endif
 
 	if (!stat) {
@@ -1301,11 +1394,11 @@
 			    stat->devno);
 		return;
 	}
-		if (ip & 0x80000001) {
+	if (ip & 0x80000001) {
 		PRINT_INFO ("%04X  caught spurious interrupt with parm %08x\n",
 			    stat->devno, ip);
-			return;
-		}
+		return;
+	}
 	cqr = (ccw_req_t *) ip;
 	device = (dasd_device_t *) cqr->device;
 	devno = device->devinfo.devno;
@@ -1341,10 +1434,11 @@
 			cqr->magic, *(int *) (&device->discipline->name));
 		return;
 	}
-		asm volatile ("STCK %0":"=m" (cqr->stopclk));
-		if ((stat->cstat == 0x00 &&
-		     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
-	    (device->discipline->examine_error &&
+	asm volatile ("STCK %0":"=m" (cqr->stopclk));
+	if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
+	     stat->cstat == 0x00 &&
+	     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
+ 	    (device->discipline->examine_error &&
 	     (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
 #ifdef ERP_DEBUG
                 if ( ++counter % 137 == 0 ) {
@@ -1353,20 +1447,20 @@
                         stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
                         stat->dstat |= 0x02;
                         goto error_fake_done;
-                        }
+                }
 #endif
 		atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
                 atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
 					 DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
                                          &device->level);
-			if (cqr->next &&
-			    (atomic_read (&cqr->next->status) ==
-			     CQR_STATUS_QUEUED)) {
-				if (dasd_start_IO (cqr->next) == 0) {
-					done_fast_io = 1;
+		if (cqr->next &&
+		    (atomic_read (&cqr->next->status) ==
+		     CQR_STATUS_QUEUED)) {
+			if (dasd_start_IO (cqr->next) == 0) {
+				done_fast_io = 1;
 			}
 		}
-		} else {	/* only visited in case of error ! */
+	} else {		/* only visited in case of error ! */
 #ifdef ERP_DEBUG
         error_fake_done:
 #endif
@@ -1375,7 +1469,7 @@
 		if (cqr->dstat) {
 			memcpy (cqr->dstat, stat, sizeof (devstat_t));
 		} else {
-				PRINT_ERR ("no memory for dstat\n");
+			PRINT_ERR ("no memory for dstat\n");
 		}
 		if (device->discipline &&
 		    device->discipline->dump_sense) {
@@ -1390,14 +1484,14 @@
 		}
 		atomic_inc (&device->queue.dirty_requests);
 		/* errorprocessing */
-			if (era == dasd_era_fatal) {
-				PRINT_WARN ("ERP returned fatal error\n");
+		if (era == dasd_era_fatal) {
+			PRINT_WARN ("ERP returned fatal error\n");
 			atomic_compare_and_swap_debug (&cqr->status,
-				     CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
-			} else {
+                                                       CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+		} else {
 			atomic_compare_and_swap_debug (&cqr->status,
                                                        CQR_STATUS_IN_IO, CQR_STATUS_ERROR);
-                        }
+		}
 	}
 	if (done_fast_io == 0)
 		atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags);
@@ -1412,56 +1506,30 @@
 	dasd_schedule_bh ();
 }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-static wait_queue_head_t watcher_queue;
-#else
-static struct wait_queue watcher_queue_Qend = {NULL,};
-static struct wait_queue *watcher_queue = &watcher_queue_Qend;
-#endif /* LINUX_IS_24 */
-
-static void
-dasd_watcher (void)
-{
-	do {
-		dasd_schedule_bh ();
-		schedule_request_fn (try_request_fn);
-		interruptible_sleep_on_timeout (&watcher_queue, 5 * HZ);
-	} while (1);
-        }
-
 /* SECTION: Some stuff related to error recovery */
 
 ccw_req_t *
 default_erp_action (ccw_req_t * cqr)
 {
 	ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
-
-	erp->cpaddr->cmd_code = CCW_CMD_NOOP;
+        
+	erp->cpaddr->cmd_code = CCW_CMD_TIC;
+        erp->cpaddr->cda = (__u32)cqr -> cpaddr;
 	erp->function = default_erp_action;
 	erp->refers = cqr;
 	erp->device = cqr->device;
         erp->magic = cqr->magic;
+        erp->retries = 16;
 	atomic_set (&erp->status, CQR_STATUS_FILLED);
-        if ( cqr->startclk && cqr->expires )
-                cqr->expires -= cqr->startclk;
-        
-	if (cqr->retries++ <= 16) {
-                atomic_compare_and_swap_debug (&cqr->status,
-                                               CQR_STATUS_ERROR,
-					       CQR_STATUS_QUEUED);
-        } else {
-		printk (KERN_WARNING PRINTK_HEADER "ERP retry count exceeded\n");
-		atomic_compare_and_swap_debug (&cqr->status,
-					       CQR_STATUS_ERROR,
-					       CQR_STATUS_FAILED);
+        if ( cqr->startclk && cqr->expires ) {
+         /*       cqr->expires -= cqr->startclk; */
 	}
-	return erp;
+        return erp;
 }
 
 int
 default_erp_postaction (ccw_req_t * cqr, int success)
 {
-	int rc = 0;
 	if (cqr->refers == NULL || cqr->function == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"ERP postaction called for non ERP cqr\n");
@@ -1471,55 +1539,183 @@
 		printk (KERN_WARNING PRINTK_HEADER
                         "default ERP postaction called for non default ERP cqr\n");
 		return -EINVAL;
-        }
-	return rc;
+	}
+        if ( success ) {
+		atomic_compare_and_swap_debug (&cqr->refers->status,
+					       CQR_STATUS_ERROR,
+					       CQR_STATUS_DONE);
+        } else {
+		atomic_compare_and_swap_debug (&cqr->refers->status,
+					       CQR_STATUS_ERROR,
+					       CQR_STATUS_FAILED);
+        } 
+	return 0;
 }
 
 /* SECTION: The helpers of the struct file_operations */
 
+/* 
+ * int dasd_format ( device* device, format_data_t *fdata )
+ * performs formatting of _device_ according to _fdata_
+ * Note: The discipline's format_function is assumed to deliver formatting
+ * commands to format a single unit of the device. In terms of the ECKD
+ * devices this means CCWs are generated to format a single track.
+ */
+
 static int
 dasd_format (dasd_device_t * device, format_data_t * fdata)
 {
-	int rc = 0;
-	int devno = device->devinfo.devno;
-	int irq = device->devinfo.irq;
-	int devindex = devindex_from_devno (devno);
-
+	int rc         = 0;
+	int devno      = device->devinfo.devno;
+	int irq        = device->devinfo.irq;
+	int devindex   = devindex_from_devno (devno);
+        ccw_req_t *req = NULL;
+        
 	if (device->open_count != 1) {
 		printk (KERN_WARNING PRINTK_HEADER
 			" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-		      " you shouldn't format a device that is already open\n",
-			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                        " you shouldn't format a device that is already open\n",
+			devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
 		return -EINVAL;
 	}
+        printk (KERN_WARNING PRINTK_HEADER
+                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                " Starting format process\n",
+                        devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
+        
         dasd_set_device_level( device->devinfo.irq,
                                DASD_DEVICE_LEVEL_RECOGNIZED,
                                device->discipline,
                                0);
-	if (device->discipline->format_device)
-          rc = device->discipline->format_device (device, fdata);
-		if (rc) {
+
+	if (device->discipline->format_device) {
+                format_data_t temp = { 
+                        fdata->start_unit, 
+                        fdata->stop_unit, 
+                        fdata->blksize, 
+                        fdata->intensity};
+                printk (KERN_WARNING PRINTK_HEADER
+                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                        " invalidating disk...\n",
+                        devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
+                
+                if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
+                     fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
+                     !(fdata -> intensity & 0x04)) {
+                        format_data_t temp2 = { 0,0,DASD_FORMAT_DEFAULT_BLOCKSIZE,0x04};
+                        req = device->discipline->format_device (device,&temp2);
+
+                        if ( req ) {
+                                rc = sleep_on_req(req);
+                                dasd_free_request(req); /* request is no longer used */
+                        } else {
+                                rc = -EINVAL;
+                        }
+                        if ( rc ) {
+                                printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n");
+                        }
+                        temp.start_unit++;
+                }
+                printk (KERN_WARNING PRINTK_HEADER
+                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                        " ...invalidation done.\n",
+                        devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
+
+                while ((!rc                                                               ) &&
+                       ((req = device->discipline->format_device (device, &temp)) != NULL )   ) {
+
+                        if ( rc=sleep_on_req(req) ) {
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                        " Formatting failed with rc = %d\n",
+                                        devno, 
+                                        irq, 
+                                        device->name, 
+                                        major_from_devindex (devindex), 
+                                        devindex << DASD_PARTN_BITS, 
+                                        rc);
+                                break;
+                        }
+                        dasd_free_request(req); /* request is no longer used */
+                        temp.start_unit++;
+                }  /* end if no more requests */
+                
+                printk (KERN_WARNING PRINTK_HEADER
+                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                        " revalidating disk...\n",
+                        devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
+
+                if (!rc          &&
+                    req  == NULL   ) {
+                        if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
+                             fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
+                             !(fdata -> intensity & 0x04)) {
+                                format_data_t temp2 = { 0,0,fdata->blksize,fdata->intensity};
+                                
+                                req = device->discipline->format_device (device, 
+                                                                         &temp2);
+                                if ( req ) {
+                                        rc = sleep_on_req(req);
+                                        dasd_free_request(req); /* request is no longer used */
+                                } else {
+                                        rc = -EINVAL;
+                                }
+                                if ( rc ) {
+                                        printk (KERN_WARNING PRINTK_HEADER "Can't revalidate Track 0\n");
+                                }
+                        }
+                }
                 printk (KERN_WARNING PRINTK_HEADER
                         " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-			" Formatting failed with rc = %d\n",
-			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
-			return rc;
-		}
-	printk (KERN_WARNING PRINTK_HEADER
-		" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-		" Formatting finished successfully rc = %d\n",
-		devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+                        " ...revalidation done\n",
+                        devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
+        } /* end if discipline->format_device */
+        printk (KERN_WARNING PRINTK_HEADER
+                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                " Formatting finished successfully\n",
+                devno, 
+                irq, 
+                device->name, 
+                major_from_devindex (devindex), 
+                devindex << DASD_PARTN_BITS);
+        
         dasd_set_device_level( device->devinfo.irq,
-                               DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                               DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
                                device->discipline,
                                0);
         udelay(1500000);
+        
         dasd_set_device_level( device->devinfo.irq,
                                DASD_DEVICE_LEVEL_ANALYSED,
                                device->discipline,
                                0);
+
 	return rc;
-}
+} /* end dasd_format */
 
 static int
 do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
@@ -1617,15 +1813,14 @@
 	case BIODASDFORMAT:{
 			/* fdata == NULL is a valid arg to dasd_format ! */
 			int partn;
-			format_data_t *fdata = NULL;
+                        format_data_t fdata = { 
+                                DASD_FORMAT_DEFAULT_START_UNIT,
+                                DASD_FORMAT_DEFAULT_STOP_UNIT,
+                                DASD_FORMAT_DEFAULT_BLOCKSIZE,
+                                DASD_FORMAT_DEFAULT_INTENSITY };
+                        
 			if (data) {
-				fdata = kmalloc (sizeof (format_data_t),
-						 GFP_ATOMIC);
-				if (!fdata) {
-					rc = -ENOMEM;
-					break;
-				}
-				rc = copy_from_user (fdata, (void *) data,
+				rc = copy_from_user (&fdata, (void *) data,
 						     sizeof (format_data_t));
 				if (rc)
 					break;
@@ -1634,15 +1829,12 @@
 			if (partn != 0) {
 				printk (KERN_WARNING PRINTK_HEADER
 					" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-				     " Cannot low-level format a partition\n",
+                                        " Cannot low-level format a partition\n",
 					device->devinfo.devno, device->devinfo.irq, device->name,
-				    MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+                                        MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
 				return -EINVAL;
 			}
-			rc = dasd_format (device, fdata);
-			if (fdata) {
-				kfree (fdata);
-			}
+			rc = dasd_format (device, &fdata);
 			break;
 		}
 	case BIODASDEXCP:{
@@ -1675,11 +1867,11 @@
 static int
 dasd_ioctl (struct inode *inp, struct file *filp,
 	    unsigned int no, unsigned long data)
-	{
+{
 	int rc = 0;
 	if ((!inp) || !(inp->i_rdev)) {
 		return -EINVAL;
-		}
+	}
 	rc = do_dasd_ioctl (inp, no, data);
 	return rc;
 }
@@ -1719,7 +1911,7 @@
 		printk (KERN_WARNING PRINTK_HEADER
 			" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 			" Cannot open unrecognized device\n",
-		     device->devinfo.devno, device->devinfo.irq, device->name,
+                        device->devinfo.devno, device->devinfo.irq, device->name,
 			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
 		return -EINVAL;
 	}
@@ -1833,7 +2025,7 @@
 	if (rc < 0) {
 		printk (KERN_WARNING PRINTK_HEADER
 		      "Cannot register to major no %d, rc = %d\n", major, rc);
-	return rc;
+		return rc;
 	} else if (rc > 0) {
 		if (major == 0) {
 			major = rc;
@@ -1950,11 +2142,11 @@
 
         if ( hd ) {
                 index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
-}
+        }
         third = index % 26;
         second = (index / 26) % 27;
 	first = ((index / 26) / 27) % 27;
-
+        
 	len = sprintf (str, "dasd");
 	if (first) {
                 len += sprintf (str + len, "%c", first + 'a' - 1 );
@@ -1968,7 +2160,7 @@
 			return -EINVAL;
 		} else {
 			len += sprintf (str + len, "%d", partition);
-	}
+		}
 	}
 	str[len] = '\0';
 	return 0;
@@ -1976,25 +2168,40 @@
 
 static void
 dasd_not_oper_handler ( int irq, int status ) {
-        int devno,devindex;
-        dasd_device_t *device;
-        devno = get_devno_by_irq(irq);
+        dasd_device_t *device=NULL;
+        major_info_t * major_info;
+        int i,devno = -ENODEV;
+
+        for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
+                for ( i = 0; i <= DASD_PER_MAJOR; i ++ ) {
+                        device = major_info->dasd_device[i];
+                        if ( device &&
+                             device -> devinfo.irq == irq ) {
+                                devno = device->devinfo.devno;
+                                break;
+                        }
+                }
+                if ( devno != -ENODEV )
+                        break;
+        }
         if ( devno < 0 ) {
-		printk (KERN_WARNING PRINTK_HEADER
-                         "not_oper_handler called on irq %d no devno!\n", irq);
-                return;
-	}
+          printk ( KERN_WARNING PRINTK_HEADER
+                   "not_oper_handler called on irq %d no devno!\n", irq);
+          return;
+        }
         printk ( KERN_INFO PRINTK_HEADER
                  "not_oper_handler called on irq %d devno %04X\n", irq,devno);
-        devindex = devindex_from_devno(devno);
-        device = find_dasd_device(devindex);
-        dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 );
+	if ( device -> open_count != 0 ) {
+		printk (KERN_ALERT PRINTK_HEADER
+			"Device %04X detached has still been open. expect errors\n", devno);
 	}
+        dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 );
+}
 
 static int
 dasd_enable_single_volume ( int irq ) {
         int rc = 0;
-        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
                                NULL, 0);
 	printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
         {
@@ -2008,14 +2215,14 @@
         }
         dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
                                NULL, 0);
-	return rc;
+        return rc;
 }
 
-static int
+int
 dasd_oper_handler ( int irq, devreg_t *devreg ) {
         int devno;
         int devindex;
-	int rc;
+        int rc;
         devno = get_devno_by_irq(irq);
         if ( devno == -ENODEV )
                 return -ENODEV;
@@ -2024,12 +2231,12 @@
                 if ( dasd_autodetect ) {
                         dasd_add_range(devno,0);
                 } else {
-		return -ENODEV;
-	}
+                        return -ENODEV;
+                }
         } while ( devindex == -ENODEV );
         rc = dasd_enable_single_volume(irq);
-		return rc;
-	}
+        return rc;
+}
 
 /* 
  * int
@@ -2061,8 +2268,8 @@
 	devindex = devindex_from_devno (devno);
 	if (devindex < 0) {
 		printk (KERN_WARNING PRINTK_HEADER " device %d is not in list of known DASDs\n", irq);
-			return -ENODEV;
-		}
+		return -ENODEV;
+	}
 	device = find_dasd_device (devindex);
         while ( (major_info = major_info_from_devindex (devindex)) == NULL ) {
                 if ((rc = dasd_register_major (major_info)) > 0) {
@@ -2072,8 +2279,8 @@
                         printk (KERN_WARNING PRINTK_HEADER
                                 "Couldn't register successfully to another major no\n");
                         return -ERANGE;
-		}
-		}
+                }
+        }
         ind = devindex & (DASD_PER_MAJOR-1);
         device = major_info->dasd_device[ind];
         if (!device) {		/* allocate device descriptor */
@@ -2108,7 +2315,7 @@
                                         if (temp->check_characteristics) {
                                                 if (temp->check_characteristics (device)) 
                                                         continue;
-	}
+                                        }
                                         discipline = temp;
                                         break;
                                 }
@@ -2119,17 +2326,25 @@
 					devno, irq, discipline->name,
                                         device->name, major_from_devindex (devindex),
 					(devindex % 64) << DASD_PARTN_BITS);
-		} else {
+			} else {
 				break;
-		}
+			}
 			device->discipline = discipline;
 			if (device->discipline->int_handler) {
+#ifdef CONFIG_DASD_DYNAMIC
                                 s390_request_irq_special(irq, 
                                                          device->discipline->int_handler, 
                                                          dasd_not_oper_handler,
                                                          0, 
                                                          DASD_NAME, 
                                                          &device->dev_status);
+#else /* !defined(CONFIG_DASD_DYNAMIC) */                             
+                                request_irq(irq, 
+                                            device->discipline->int_handler, 
+                                            0, 
+                                            DASD_NAME, 
+                                            &device->dev_status);
+#endif /* CONFIG_DASD_DYNAMIC */                             
 			}
 			atomic_compare_and_swap_debug (&device->level,
                                                        DASD_DEVICE_LEVEL_UNKNOWN,
@@ -2149,13 +2364,13 @@
                                                                                DASD_DEVICE_LEVEL_RECOGNIZED,
                                                                                DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
                                                 s390irq_spin_unlock_irqrestore (irq, flags);
-}
+                                        }
                                 }
                         } else {
                                 atomic_compare_and_swap_debug (& device->level,DASD_DEVICE_LEVEL_RECOGNIZED,
                                                                DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
                         }
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
+			if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
 				break;
 		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
 			return -EAGAIN;
@@ -2170,7 +2385,7 @@
 			case 4096:
 				break;
 			default:
-{
+                        {
 					printk (KERN_INFO PRINTK_HEADER
 						"/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
 						" Did you format the drive?\n",
@@ -2220,19 +2435,6 @@
 		}
 	} else 	if (desired_level < current_level) {		/* donwgrade device status */
 		switch (current_level) {
-		case DASD_DEVICE_LEVEL_PARTITIONED:	/* Fallthrough ?? */
-                        /* delete the partition information */
-			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-                                struct hd_struct *p = &major_info->gendisk.part[minor+i];
-                                p->start_sect = 0;
-                                p->nr_sects = 0;
-                                p->type = 0;
-                        }
-			atomic_compare_and_swap_debug (&device->level,
-                                                       DASD_DEVICE_LEVEL_PARTITIONED,
-                                                       DASD_DEVICE_LEVEL_ANALYSED);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
-				break;
 		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
 			atomic_compare_and_swap_debug (&device->level,
                                                        DASD_DEVICE_LEVEL_ANALYSED,
@@ -2315,7 +2517,7 @@
 #endif /* KERNEL_VERSION */
 static struct proc_dir_entry* dasd_devices_entry;
 
-
+	
 static int
 dasd_devices_open (struct inode* inode, struct file*  file )
 {
@@ -2331,7 +2533,7 @@
                 return -ENOMEM;
 	} else {
                 file->private_data = (void *)info;
-	}
+        }
         while ( temp ) {
                 int i;
                 for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) {
@@ -2393,7 +2595,7 @@
 		temp = temp->next;
 	}
         info->len=len;
-	return rc;
+        return rc;
 }
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
@@ -2407,41 +2609,59 @@
         if(*offset >= p_info->len)
         {
                 return 0; /* EOF */
-	}
+        }
         else
         {
                 len = MIN(user_len, (p_info->len - *offset));
                 copy_to_user(user_buf, &(p_info->data[*offset]), len);
                 (*offset) += len;
                 return len;  /* number of bytes "read" */
+        }
+}
+
+static ssize_t 
+dasd_devices_write (  struct  file *file, const char*   user_buf,  size_t  user_len, loff_t* offset )
+{
+        char * buffer = vmalloc(user_len);
+
+        if ( buffer == NULL)
+                return -ENOMEM;
+        copy_from_user ( buffer, user_buf, user_len);
+        buffer[user_len] = 0;
+        printk ( KERN_INFO PRINTK_HEADER "Now executing %s\n",buffer);
+	if ( ! strncmp(buffer,"add range",strlen("add_range"))) {
+
+	} else if ( ! strncmp(buffer,"enable device",strlen("enable device"))) {
+
+	} else if ( ! strncmp(buffer,"disable device",strlen("disable device"))) {
+
+	} else {
+		printk (KERN_WARNING PRINTK_HEADER "unknown command %s",
+			buffer );
 	}
+        vfree(buffer);
+        return user_len;
 }
 
-static int
+static int 
 dasd_devices_close (struct inode* inode, struct file*  file)
 {
-	int rc = 0;
+        int rc = 0;
         tempinfo_t* p_info = (tempinfo_t*)file->private_data;
         if ( p_info ) {
                 if ( p_info->data ) vfree(p_info->data);
                 vfree(p_info);
-	}
-	return rc;
+        }
+        return rc;
 }
 
 
 static struct file_operations dasd_devices_file_ops =
 {
-  NULL,          /* lseek */
-  dasd_devices_read,  /* read */
-  NULL, /* dasd_devices_write, */   /* write */
-  NULL,          /* readdir */
-  NULL,          /* select */
-  NULL,          /* ioctl */
-  NULL,          /* mmap */
-  dasd_devices_open,    /* open */
-  NULL,          /* flush */
-  dasd_devices_close,   /* close */
+  read: dasd_devices_read,  /* read */
+  write: dasd_devices_write,   /* write */
+  open: dasd_devices_open,    /* open */
+  release: dasd_devices_close,   /* close */
 };
 
 static struct inode_operations dasd_devices_inode_ops =
@@ -2451,16 +2671,17 @@
 #endif /* LINUX_IS_24 */
 };
 
-void
+int
 dasd_proc_init (void)
 {
+        int rc = 0;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-        dasd_proc_root_entry = create_proc_entry("dasd", 
-                                                 S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR,
-                                                 &proc_root);
+        dasd_proc_root_entry = proc_mkdir("dasd",&proc_root);
         dasd_devices_entry = create_proc_entry("devices", 
                                                S_IFREG | S_IRUGO | S_IWUSR,
                                                dasd_proc_root_entry);
+        dasd_devices_entry -> proc_fops = &dasd_devices_file_ops;
+        dasd_devices_entry -> proc_iops = &dasd_devices_inode_ops;
 #else
 	proc_register (&proc_root, &dasd_proc_root_entry);
 	dasd_devices_entry = (struct proc_dir_entry*)kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
@@ -2479,6 +2700,7 @@
                 proc_register(&dasd_proc_root_entry, dasd_devices_entry);
         }
 #endif /* LINUX_IS_24 */
+        return rc;
 }
 
 void
@@ -2506,15 +2728,13 @@
         dasd_range_t *range;
 
 	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
-        genhd_dasd_name = dasd_device_name;
 #ifndef MODULE
         dasd_split_parm_string(dasd_parm_string);
 #endif /* ! MODULE */
         dasd_parse(dasd);
 
-        dasd_proc_init();
         dasd_init_emergency_req();
-
+       
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
         init_waitqueue_head(&watcher_queue);
         spin_lock_init(&cq_lock);
@@ -2527,72 +2747,115 @@
 		} else {
 			printk (KERN_WARNING PRINTK_HEADER
 				"Couldn't register successfully to major no %d\n", major_info->gendisk.major);
-	}
+                        /* revert registration of major infos */
+                        goto major_failed;
 		}
+	}
+        rc = dasd_proc_init();
+        if ( rc ) {
+                goto proc_failed;
+        }
+
+        genhd_dasd_name = dasd_device_name;
         
 #ifdef CONFIG_DASD_ECKD
 	rc = dasd_eckd_init ();
 	if (rc==0)  {
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered ECKD discipline successfully\n");
-	}
+	} else {
+                goto eckd_failed;
+        }
 #endif				/* CONFIG_DASD_ECKD */
 #ifdef CONFIG_DASD_FBA
 	rc = dasd_fba_init ();
 	if (rc == 0) {
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered FBA discipline successfully\n");
+	} else {
+                goto fba_failed;
 	}
 #endif				/* CONFIG_DASD_FBA */
 #ifdef CONFIG_DASD_MDSK
-	rc = dasd_diag_init ();
-	if (rc == 0)  {
+        if ( MACHINE_IS_VM ) {
+            rc = dasd_diag_init ();
+            if (rc == 0)  {
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered MDSK discipline successfully\n");
-	}
+            } else {
+                goto mdsk_failed;
+            }
+        }
 #endif				/* CONFIG_DASD_MDSK */
 	rc = 0;
 	for (range = dasd_range_head; range; range= range->next) {
 		for (j = range->from; j <= range->to; j++) {
 			irq = get_irq_by_devno (j);
 			if (irq >= 0)
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
 						       NULL, 0);
+		}
 	}
-			}
         if ( dasd_autodetect ) {
                 for ( irq = get_irq_first(); irq != -ENODEV; irq = get_irq_next(irq) ) {
                         int devno = get_devno_by_irq(irq);
                         int index = devindex_from_devno(devno);
                         if ( index == -ENODEV ) { /* not included in ranges */
                                 dasd_add_range (devno,0);
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
 						       NULL, 0);
-		}
-	}
-}
+                        }
+                }
+        }
 	printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
-{
+        {
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
                 static wait_queue_head_t wait_queue;
                 init_waitqueue_head(&wait_queue);
 #else
                 static struct wait_queue *wait_queue = NULL;
 #endif /* LINUX_IS_24 */
-                interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 );
-	}
+                interruptible_sleep_on_timeout (&wait_queue,
+                                                (20 * HZ) >> 1 );
+        }
 	for (range = dasd_range_head; range; range= range->next) {
 		for (j = range->from; j <= range->to; j++) {
 			irq = get_irq_by_devno (j);
 			if (irq >= 0) {
 				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
 						       NULL, 0);
-	}
+                        }
 		}
 	}
-
-	printk (KERN_INFO PRINTK_HEADER "initialization completed\n");
-	return rc;
+        goto out;
+#ifdef CONFIG_DASD_MDSK
+ mdsk_failed:
+	dasd_diag_cleanup ();
+#endif				/* CONFIG_DASD_MDSK */
+#ifdef CONFIG_DASD_FBA
+ fba_failed:
+	dasd_fba_cleanup ();
+#endif				/* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_ECKD
+ eckd_failed:
+	dasd_eckd_cleanup ();
+#endif				/* CONFIG_DASD_ECKD */
+ proc_failed:
+        dasd_proc_cleanup();
+ major_failed: {
+                for (major_info = dasd_major_info; 
+                     major_info;
+                     major_info = major_info->next) {
+                        dasd_unregister_major(major_info);
+                }
+        }
+ emergency_failed:
+        dasd_cleanup_emergency_req();
+ failed:
+        printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
+ out:
+        printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
+        return rc;
 }
 
 void
@@ -2615,7 +2878,7 @@
 				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
 						       NULL, 0);
                                 kfree(find_dasd_device(devindex_from_devno(j)));
-			}
+                        }
 		}
 	}
 	for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
@@ -2634,19 +2897,19 @@
                 next = range -> next;
                 kfree (range);
                 if ( next == NULL )
-			break;
+                        break;
                 else
                         range = next;
-		}
+        } 
         dasd_range_head = NULL;
 
         while ( dasd_devreg_head ) {
                 reg = dasd_devreg_head->next;
                 kfree ( dasd_devreg_head );
                 dasd_devreg_head = reg;
-	}
+        }
 	printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
-	}
+}
 
 #ifdef MODULE
 int
@@ -2655,7 +2918,7 @@
         int rc=0;
         return dasd_init(); 
         return rc;
-	}
+}
 
 void 
 cleanup_module ( void ) 
diff -urN linux-2.2.18-pre20/drivers/s390/block/dasd.h linux/drivers/s390/block/dasd.h
--- linux-2.2.18-pre20/drivers/s390/block/dasd.h	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/dasd.h	Mon Dec  3 22:14:17 2001
@@ -5,6 +5,5 @@
 ccw_req_t * dasd_alloc_request (char *, int , int ) ;
 void dasd_free_request(ccw_req_t *);
 int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
-
-
+int dasd_oper_handler ( int irq, devreg_t *devreg );
 
diff -urN linux-2.2.18-pre20/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- linux-2.2.18-pre20/drivers/s390/block/dasd_3990_erp.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/dasd_3990_erp.c	Mon Dec  3 22:14:17 2001
@@ -64,13 +64,22 @@
 dasd_3990_erp_examine_24 (char *sense)
 {
 
-	/* check for 'Command Recejct' which is always a fatal error  */
+	/* check for 'Command Recejct' whithout environmental data present  */
 	if (sense[0] & 0x80) {
-		return dasd_era_fatal;
-	}
-	/* check for 'Invalid Track Format'                           */
+                if (sense[2] &0x10){
+                        return dasd_era_recover;
+                } else {
+                        return dasd_era_fatal;
+                }
+        }
+	
+        /* check for 'Invalid Track Format' whithout environmental data present  */
 	if (sense[1] & 0x40) {
-		return dasd_era_fatal;
+                if (sense[2] &0x10){
+                        return dasd_era_recover;
+                } else {
+                        return dasd_era_fatal;
+                }
 	}
 	/* check for 'No Record Found'                                */
 	if (sense[1] & 0x08) {
diff -urN linux-2.2.18-pre20/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c
--- linux-2.2.18-pre20/drivers/s390/block/dasd_diag.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/dasd_diag.c	Mon Dec  3 22:14:17 2001
@@ -5,6 +5,10 @@
  * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+	
+ * History of changes
+ * 07/13/00 Added fixup sections for diagnoses ans saved some registers
+ * 07/14/00 fixed constraints in newly generated inline asm
  */
 
 #include <linux/stddef.h>
@@ -20,6 +24,7 @@
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/s390dyn.h>
 
 #include "dasd.h"
 #include "dasd_diag.h"
@@ -47,13 +52,24 @@
 {
 	int rc;
 
-	__asm__ __volatile__ ("    lr    2,%1\n"
-                              "    .long 0x83200210\n"
+	__asm__ __volatile__ ("    diag  %1,0,0x210\n"
                               "0:  ipm   %0\n"
-                              "    srl   %0,28"
+                              "    srl   %0,28\n"
+                              "1:\n"
+                              ".section .fixup,\"ax\"\n"
+                              "2:  lhi   %0,3\n"
+                              "    bras  1,3f\n"
+                              "    .long 1b\n"
+                              "3:  l     1,0(1)\n"
+                              "    br    1\n"
+                              ".previous\n"
+                              ".section __ex_table,\"a\"\n"
+                              "    .align 4\n"
+                              "    .long 0b,2b\n"
+                              ".previous\n"
                               :"=d" (rc)
                               :"d" ((void *) __pa (devchar))
-                              :"2");
+                              :"1");
 	return rc;
 }
 
@@ -62,13 +78,23 @@
 {
 	int rc;
 
-	__asm__ __volatile__ ("    lr    2,%1\n"
-                              "    lr    3,%2\n"
-                              "    .long 0x83230250\n"
-                              "    lr    %0,3"
-                              :"=d" (rc)
-                              :"d" ((void *) __pa (iob)), "d" (cmd)
-                              :"2", "3");
+	__asm__ __volatile__ ("    lr    1,%1\n"
+                              "    diag  1,%2,0x250\n"
+                              "1:\n"
+                              ".section .fixup,\"ax\"\n"
+                              "2:  lhi   %0,3\n"
+                              "    bras  1,3f\n"
+                              "    .long 1b\n"
+                              "3:  l     1,0(1)\n"
+                              "    br    1\n"
+                              ".previous\n"
+                              ".section __ex_table,\"a\"\n"
+                              "    .align 4\n"
+                              "    .long 1b,2b\n"
+                              ".previous\n"
+                              : "=d" (rc)
+                              : "d" ((void *) __pa (iob)), "0" (cmd)
+                              : "1" );
 	return rc;
 }
 
@@ -528,6 +554,23 @@
           ctl_set_bit (0, 9);
           register_external_interrupt (0x2603, dasd_ext_handler);
           dasd_discipline_enq(&dasd_diag_discipline);
+        } else {
+          printk ( KERN_INFO PRINTK_HEADER
+                   "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
+          rc = -EINVAL;
+        }
+        return rc;
+}
+
+void
+dasd_diag_cleanup( void ) {
+        int rc = 0;
+        if ( MACHINE_IS_VM ) {
+          printk ( KERN_INFO PRINTK_HEADER
+                   "%s discipline cleaning up\n", dasd_diag_discipline.name);
+          dasd_discipline_deq(&dasd_diag_discipline);
+          unregister_external_interrupt (0x2603, dasd_ext_handler);
+          ctl_clear_bit (0, 9);
         } else {
           printk ( KERN_INFO PRINTK_HEADER
                    "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
diff -urN linux-2.2.18-pre20/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- linux-2.2.18-pre20/drivers/s390/block/dasd_eckd.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/dasd_eckd.c	Mon Dec  3 22:14:17 2001
@@ -6,6 +6,12 @@
 
  * History of changes (starts July 2000)
  * 07/11/00 Enabled rotational position sensing
+ * 07/14/00 Reorganized the format process for better ERP
+ * 07/20/00 added experimental support for 2105 control unit (ESS)
+ * 07/24/00 increased expiration time and added the missing zero
+ * 08/07/00 added some bits to define_extent for ESS support
+ * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF)
+ * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages)
  */
 
 #include <linux/stddef.h>
@@ -21,6 +27,7 @@
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/s390dyn.h>
 
 #include "dasd.h"
 #include "dasd_eckd.h"
@@ -32,15 +39,15 @@
 #define PRINTK_HEADER DASD_NAME"(eckd):"
 
 #define ECKD_C0(i) (i->home_bytes)
-#define ECKD_F(i) (i -> formula)
+ #define ECKD_F(i) (i->formula)
 #define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))
 #define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))
 #define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))
 #define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
 #define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
-#define ECKD_F6(i) (i -> factor6)
-#define ECKD_F7(i) (i -> factor7)
-#define ECKD_F8(i) (i -> factor8)
+#define ECKD_F6(i) (i->factor6)
+#define ECKD_F7(i) (i->factor7)
+#define ECKD_F8(i) (i->factor8)
 
 #define DASD_ECKD_CCW_WRITE 0x05
 #define DASD_ECKD_CCW_READ 0x06
@@ -67,6 +74,25 @@
         eckd_count_t count_area;
 } dasd_eckd_private_t;
 
+static
+devreg_t dasd_eckd_known_devices[] = {
+	{
+		ci : { hc: { ctype: 0x3990, dtype: 0x3390 } }, 
+		flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+		oper_func: dasd_oper_handler
+	},
+        {
+                ci : { hc: { ctype: 0x3990, dtype: 0x3380 } },
+                flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+                oper_func: dasd_oper_handler
+        },
+        {
+                ci : { hc: { ctype: 0x9343, dtype: 0x9345 } },
+                flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+                oper_func: dasd_oper_handler
+        }
+};
+
 static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
 {
@@ -133,15 +159,15 @@
 {
 	int rpt = 0;
 	int dn;
-        switch ( rdc -> dev_type ) {
-	case 0x3380: 
+	switch (rdc->dev_type) {
+	case 0x3380:
 		if (kl)
 			return 1499 / (15 +
 				       7 + ceil_quot (kl + 12, 32) +
 				       ceil_quot (dl + 12, 32));
 		else
 			return 1499 / (15 + ceil_quot (dl + 12, 32));
-	case 0x3390: 
+	case 0x3390:
 		dn = ceil_quot (dl + 6, 232) + 1;
 		if (kl) {
 			int kn = ceil_quot (kl + 6, 232) + 1;
@@ -151,16 +177,16 @@
 		} else
 			return 1729 / (10 +
 				       9 + ceil_quot (dl + 6 * dn, 34));
-	case 0x9345: 
-	        dn = ceil_quot (dl + 6, 232) + 1;
-                if (kl) {
-                        int kn = ceil_quot (kl + 6, 232) + 1;
-                        return 1420 / (18 +
-                                       7 + ceil_quot (kl + 6 * kn, 34) +
-                                       ceil_quot (dl + 6 * dn, 34));
-                } else
-                        return 1420 / (18 +
-                                       7 + ceil_quot (dl + 6 * dn, 34));
+	case 0x9345:
+		dn = ceil_quot (dl + 6, 232) + 1;
+		if (kl) {
+			int kn = ceil_quot (kl + 6, 232) + 1;
+			return 1420 / (18 +
+				       7 + ceil_quot (kl + 6 * kn, 34) +
+				       ceil_quot (dl + 6 * dn, 34));
+		} else
+			return 1420 / (18 +
+				       7 + ceil_quot (dl + 6 * dn, 34));
 	}
 	return rpt;
 }
@@ -186,7 +212,7 @@
 	memset (de_ccw, 0, sizeof (ccw1_t));
 	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
 	de_ccw->count = 16;
-	de_ccw->cda = (void *) __pa (data);
+	de_ccw->cda = (__u32) __pa (data);
 
 	memset (data, 0, sizeof (DE_eckd_data_t));
 	switch (cmd) {
@@ -198,12 +224,12 @@
 	case DASD_ECKD_CCW_READ_CKD_MT:
 	case DASD_ECKD_CCW_READ_COUNT:
 		data->mask.perm = 0x1;
-                data->attributes.operation = 0x3; /* enable seq. caching */
+		data->attributes.operation = 0x3;	/* enable seq. caching */
 		break;
 	case DASD_ECKD_CCW_WRITE:
 	case DASD_ECKD_CCW_WRITE_MT:
 		data->mask.perm = 0x02;
-                data->attributes.operation = 0x3; /* enable seq. caching */
+		data->attributes.operation = 0x3;	/* enable seq. caching */
 		break;
 	case DASD_ECKD_CCW_WRITE_CKD:
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
@@ -220,6 +246,9 @@
 		break;
 	}
 	data->attributes.mode = 0x3;
+	if ( private -> rdc_data.cu_type == 0x2105 ) {
+		data -> reserved |= 0x40;
+	}
 	data->beg_ext.cyl = beg.cyl;
 	data->beg_ext.head = beg.head;
 	data->end_ext.cyl = end.cyl;
@@ -233,19 +262,19 @@
 	       int rec_on_trk,
 	       int no_rec,
 	       int cmd,
-	       dasd_device_t * device)
+	       dasd_device_t * device,
+               int reclen)
 {
         dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
 	ch_t geo = {private->rdc_data.no_cyl,
                     private->rdc_data.trk_per_cyl};
 	ch_t seek ={trk / (geo.head), trk % (geo.head)};
-	int reclen = device->sizes.bp_block;
         int sector;
 
 	memset (lo_ccw, 0, sizeof (ccw1_t));
 	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	lo_ccw->count = 16;
-	lo_ccw->cda = (void *) __pa (data);
+	lo_ccw->cda = (__u32) __pa (data);
 
 	memset (data, 0, sizeof (LO_eckd_data_t));
 	switch (cmd) {
@@ -293,7 +322,7 @@
 		break;
 	case DASD_ECKD_CCW_READ_COUNT:
 		data->operation.operation = 0x06;
-                break;
+		break;
 	default:
 		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
 	}
@@ -325,17 +354,19 @@
 static int 
 dasd_eckd_id_check ( dev_info_t *info )
 {
-        if ( info->sid_data.cu_type == 0x3990 )
+        if ( info->sid_data.cu_type == 0x3990 ||
+	     info->sid_data.cu_type == 0x2105 )
                 if ( info->sid_data.dev_type == 0x3390 )
                         return 0;
-        if ( info->sid_data.cu_type == 0x3990 )
+        if ( info->sid_data.cu_type == 0x3990 ||
+	     info->sid_data.cu_type == 0x2105 )
                 if ( info->sid_data.dev_type == 0x3380 )
                         return 0;
         if ( info->sid_data.cu_type == 0x9343 )
                 if ( info->sid_data.dev_type == 0x9345 )
                         return 0;
         return -ENODEV;
-		}
+}
 
 static int
 dasd_eckd_check_characteristics (struct dasd_device_t *device)
@@ -366,7 +397,7 @@
                 printk ( KERN_WARNING PRINTK_HEADER
                          "Read device characteristics returned error %d\n",rc);
                 return rc;
-	}
+        }
 	printk ( KERN_INFO PRINTK_HEADER 
                  "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n",
                  device->devinfo.devno, device->devinfo.irq,
@@ -381,7 +412,7 @@
                 printk ( KERN_WARNING PRINTK_HEADER
                          "Read configuration data returned error %d\n",rc);
                 return rc;
-	}
+        }
         if ( conf_len != sizeof(dasd_eckd_confdata_t)) {
                 printk ( KERN_WARNING PRINTK_HEADER
                          "sizes of configuration data mismatch %d (read) vs %ld (expected)\n",
@@ -429,13 +460,14 @@
 	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
 	ccw->flags = CCW_FLAG_CC;
 	ccw++;
-	locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, device);
+	locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device,0);
 	ccw->flags = CCW_FLAG_CC;
 	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
 	ccw->count = 8;
-	ccw->cda = (void *) __pa (count_data);
+	ccw->cda = (__u32) __pa (count_data);
 	cqr->device = device;
+        cqr->retries = 0;
 	atomic_set (&cqr->status, CQR_STATUS_FILLED);
         
         return cqr;
@@ -511,10 +543,9 @@
         return rc;
 }
 
-static inline int
-dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags)
+static ccw_req_t *
+dasd_eckd_format_device (dasd_device_t *device, format_data_t *fdata)
 {
-	int rc = 0;
 	int i;
 	ccw_req_t *fcp = NULL;
 	DE_eckd_data_t *DE_data = NULL;
@@ -525,252 +556,177 @@
 	ccw1_t *last_ccw = NULL;
         void * last_data = NULL;
         dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
-	int retries;
-
+        int trk = fdata -> start_unit;
+        int bs = fdata -> blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize;
+        int flags = fdata -> intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata -> intensity;
+        
 	int rpt = recs_per_track (&(private->rdc_data), 0, bs);
 	int cyl = trk / private->rdc_data.trk_per_cyl;
 	int head = trk % private->rdc_data.trk_per_cyl;
         int wrccws = rpt;
         int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
         
+        
+        if ( ( (fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) &&
+               trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl ) ) ||
+             ( (fdata -> stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) &&
+               trk > fdata->stop_unit ) ) {
+                printk (KERN_WARNING PRINTK_HEADER "Track %d reached...ending!\n",trk);
+                return NULL;
+        }
+        switch(bs) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default: 
+                printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n",bs);
+                return NULL;
+        }
         switch ( flags ) {
         case 0x00:
         case 0x01:
         case 0x03:
-          break;
+        case 0x04: /* make track invalid */
+                break;
         default:
-          return -EINVAL;
+                printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n",flags);
+                return NULL;
+        }
+
+        /* print status line */
+        if ( (private->rdc_data.no_cyl < 20          ) ?
+	     ( trk % private->rdc_data.no_cyl == 0   ) :
+             ( trk % private->rdc_data.no_cyl == 0 &&
+               (trk / private->rdc_data.no_cyl) % 
+	       (private->rdc_data.no_cyl / 20 )      )  ) {
+
+                printk (KERN_INFO PRINTK_HEADER
+                        "Format %04X Cylinder: %d Flags: %d\n", 
+                        device->devinfo.devno,
+                        trk / private->rdc_data.trk_per_cyl,
+                        flags);
         }
         
-        if ( flags & 0x1 ) {
-          wrccws++;
-          datasize += sizeof(eckd_count_t);
-        }
-        if ( flags & 0x2 ) {
-          wrccws++;
-          datasize += sizeof(eckd_home_t);
+        if ( flags & 0x04) {
+                rpt = 1;
+                wrccws = 1;
+        } else {
+                if ( flags & 0x1 ) {
+                        wrccws++;
+                        datasize += sizeof(eckd_count_t);
+                }
+                if ( flags & 0x2 ) {
+                        wrccws++;
+                        datasize += sizeof(eckd_home_t);
+                }
         }
 	fcp = ccw_alloc_request (dasd_eckd_discipline.name, 
                                  wrccws + 2,
                                  datasize+rpt*sizeof(eckd_count_t));
-	fcp->device = device;
-
-        last_data = fcp->data;
-	DE_data = (DE_eckd_data_t *) last_data;
-        last_data = (void*)(DE_data +1);
-	LO_data = (LO_eckd_data_t *) last_data;
-        last_data = (void*)(LO_data +1);
-        if ( flags & 0x2 ) {
-          ha_data = (eckd_home_t *) last_data;
-          last_data = (void*)(ha_data +1);
-        }
-        if ( flags & 0x1 ) {
-          r0_data = (eckd_count_t *) last_data;
-          last_data = (void*)(r0_data +1);
-        }
-	ct_data = (eckd_count_t *)last_data;
-
-	last_ccw = fcp->cpaddr;
-
-	switch (flags) {
-	case 0x03:
-		define_extent (last_ccw, DE_data, trk, trk,
-                               DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
-		last_ccw->flags = CCW_FLAG_CC;
-		last_ccw++;
-		locate_record (last_ccw, LO_data, trk, 0, wrccws,
-			       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
-		last_ccw->flags = CCW_FLAG_CC;
-		last_ccw++;
-		break;
-	case 0x01:
-		define_extent (last_ccw, DE_data, trk, trk,
-			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
-		last_ccw->flags = CCW_FLAG_CC;
-		last_ccw++;
-		locate_record (last_ccw, LO_data, trk, 0, wrccws,
+        if ( fcp != NULL ) {
+                fcp->device = device;
+                last_data = fcp->data;
+                DE_data = (DE_eckd_data_t *) last_data;
+                last_data = (void*)(DE_data +1);
+                LO_data = (LO_eckd_data_t *) last_data;
+                last_data = (void*)(LO_data +1);
+                if ( flags & 0x2 ) {
+                        ha_data = (eckd_home_t *) last_data;
+                        last_data = (void*)(ha_data +1);
+                }
+                if ( flags & 0x1 ) {
+                        r0_data = (eckd_count_t *) last_data;
+                        last_data = (void*)(r0_data +1);
+                }
+                ct_data = (eckd_count_t *)last_data;
+                
+                last_ccw = fcp->cpaddr;
+                
+                switch (flags) {
+                case 0x03:
+                        define_extent (last_ccw, DE_data, trk, trk,
+                                       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                                       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,device->sizes.bp_block );
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        break;
+                case 0x01:
+                        define_extent (last_ccw, DE_data, trk, trk,
 			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
-		last_ccw->flags = CCW_FLAG_CC;
-		last_ccw++;
-		memset (r0_data, 0, sizeof (eckd_count_t));
-		break;
-	case 0x00:
-		define_extent (last_ccw, DE_data, trk, trk,
-			       DASD_ECKD_CCW_WRITE_CKD, device);
-		last_ccw->flags = CCW_FLAG_CC;
-		last_ccw++;
-		locate_record (last_ccw, LO_data, trk, 0, wrccws,
-			       DASD_ECKD_CCW_WRITE_CKD, device);
-                LO_data->length = bs;
-		last_ccw->flags = CCW_FLAG_CC;
-		last_ccw++;
-		break;
-	default:
-		PRINT_WARN ("Unknown format flags...%d\n", flags);
-		return -EINVAL;
-	}
-	if (flags & 0x02) {
-		PRINT_WARN ("Unsupported format flag...%d\n", flags);
-		return -EINVAL;
-	}
-	if (flags & 0x01) {	/* write record zero */
-		r0_data->cyl = cyl;
-		r0_data->head = head;
-		r0_data->record = 0;
-		r0_data->kl = 0;
-		r0_data->dl = 8;
-		last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
-		last_ccw->count = 8;
-		last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
-		last_ccw->cda = (void *) __pa (r0_data);
-		last_ccw++;
-	}
-	/* write remaining records */
-	for (i = 0; i < rpt; i++, last_ccw++) {
-		memset (ct_data + i, 0, sizeof (eckd_count_t));
-		(ct_data + i)->cyl = cyl;
-		(ct_data + i)->head = head;
-		(ct_data + i)->record = i + 1;
-		(ct_data + i)->kl = 0;
-		(ct_data + i)->dl = bs;
-		last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
-		last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
-		last_ccw->count = 8;
-		last_ccw->cda = (void *) __pa (ct_data + i);
-	}
-	(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
-	fcp->device = device;
-        do {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-                DECLARE_WAITQUEUE (wait,current);
-#else
-                struct wait_queue wait = {current, NULL};
-#endif /* LINUX_VERSION_CODE */
-                unsigned long flags;
-                int cs;
-
-                retries = 1;
-		s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-                atomic_set(&fcp->status,CQR_STATUS_QUEUED);
-                do {
-                        rc = dasd_eckd_discipline.start_IO (fcp);
-                } while ( rc && retries-- );
-                if ( rc && retries == 0 )
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                                       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,device->sizes.bp_block);
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        memset (r0_data, 0, sizeof (eckd_count_t));
                         break;
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-		add_wait_queue (&device->wait_q, &wait);
-#endif /* LINUX_VERSION_CODE */
-		do {
-			current->state = TASK_INTERRUPTIBLE;
-			s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-                        schedule ();
-			s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-                        cs = atomic_read (&fcp->status);
-		} while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_ERROR));
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-		remove_wait_queue (&device->wait_q, &wait);
-#endif /* LINUX_VERSION_CODE */
-		s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-	} while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) &&
-                 retries--);
-	if ( retries == 0 )
-                rc = -EIO;
-	ccw_free_request (fcp);
-	return rc;
-}
-
-static int
-dasd_eckd_format_device (struct dasd_device_t *device, struct format_data_t *fdata)
-{
-        int rc = 0;
-	int i;
-	format_data_t fd;
-        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
-        int last_track =private->rdc_data.no_cyl*private->rdc_data.trk_per_cyl-1;
-        int intensity;
-        kdev_t kdev = device->kdev;
-        int nr_tracks, blocksize;
-
-	if (fdata==NULL) {
-		fd.start_unit = 0;
-		fd.stop_unit = last_track;
-		fd.blksize = 4096;
-	} else {
-		memcpy (&fd, fdata, sizeof (format_data_t));
-		if (fd.stop_unit == -1) {
-			fd.stop_unit = last_track;
-		}
-		if (fd.blksize == 0) {
-			fd.blksize = 4096;
-		}
-	}
-	if (fd.start_unit > fd.stop_unit) {
-		return -EINVAL;
-	}
-	if (fd.start_unit > last_track ) {
-		return -EINVAL;
-	}
-	if (fd.stop_unit > last_track ) {
-		return -EINVAL;
-	}
-        switch(fd.blksize) {
-        case 512:
-        case 1024:
-        case 2048:
-        case 4096:
-                break;
-        default:
-                return -EINVAL;
-        }
-        fd.intensity = 0x0;
-        intensity = fd.intensity;
-        set_blocksize(kdev, fd.blksize);
-	printk (KERN_INFO PRINTK_HEADER
-                "Formatting device %04X from track %d to %d with bs %d\n",
-                device->devinfo.devno,fd.start_unit, fd.stop_unit, fd.blksize);
-        nr_tracks = fd.stop_unit-fd.start_unit+1;
-	for (i = 0; i <= nr_tracks; i++) {
-		/* print 20 messages per format cmd at all */
-                if ( i % (nr_tracks / 20) == 0 ) { 
-                        printk (KERN_INFO PRINTK_HEADER
-                                "Format %04X Cylinder: %d Track %d Intensity %d\n", 
-                                device->devinfo.devno,
-                                (i+fd.start_unit) / private->rdc_data.trk_per_cyl,
-                                (i+fd.start_unit) % private->rdc_data.trk_per_cyl,
-                                intensity);
-                }
-                do {
-                        if ( i == 0 ) {
-                                blocksize = 8;
-                        } else {
-                                blocksize = fd.blksize;
-                        }
-                        rc = dasd_eckd_format_track (device, 
-                                                     (i % nr_tracks) + fd.start_unit , 
-                                                     blocksize, intensity);
-                                /* fix VM controlled minidisk */
-                        if ( rc ) {
-                                if ( intensity ) {
-                                        intensity = intensity >> 1;
-                                }
-                                printk (KERN_WARNING PRINTK_HEADER
-                                        "decreasing format intensity to %d\n", 
-                                        intensity);
-                        }
-                } while ( rc && intensity > 0);
-                if (rc) {
-                        printk (KERN_WARNING PRINTK_HEADER
-                                "Formatting of device %04X Cylinder %d Track %d failed...exiting\n",
-                                device->devinfo.devno,
-                                i / private->rdc_data.trk_per_cyl,
-                                i % private->rdc_data.trk_per_cyl);
+                case 0x04:
+                        define_extent (last_ccw, DE_data, trk, trk,
+                                       DASD_ECKD_CCW_WRITE_CKD, device);
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                                       DASD_ECKD_CCW_WRITE_CKD, device,0);
+                        LO_data->length = bs;
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
                         break;
-		}
-	}
-	printk ( KERN_INFO PRINTK_HEADER
-                 "Formatting of device %04X completed from track %d to %d with bs %d\n",
-                 device->devinfo.devno, fd.start_unit, fd.stop_unit, fd.blksize);
-        return rc;
+                case 0x00:
+                        define_extent (last_ccw, DE_data, trk, trk,
+                                       DASD_ECKD_CCW_WRITE_CKD, device);
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                                       DASD_ECKD_CCW_WRITE_CKD, device,device->sizes.bp_block);
+                        LO_data->length = bs;
+                        last_ccw->flags = CCW_FLAG_CC;
+                        last_ccw++;
+                        break;
+                default:
+                        PRINT_WARN ("Unknown format flags...%d\n", flags);
+                        return NULL;
+                }
+                if (flags & 0x02 ) {
+                        PRINT_WARN ("Unsupported format flag...%d\n", flags);
+                        return NULL; 
+                }
+                if (flags & 0x01) {	/* write record zero */
+                        r0_data->cyl = cyl;
+                        r0_data->head = head;
+                        r0_data->record = 0;
+                        r0_data->kl = 0;
+                        r0_data->dl = 8;
+                        last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
+                        last_ccw->count = 8;
+                        last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+                        last_ccw->cda = (__u32) __pa (r0_data);
+                        last_ccw++;
+                }
+                /* write remaining records */
+                for (i = 0; i < rpt; i++) {
+                        memset (ct_data + i, 0, sizeof (eckd_count_t));
+                        (ct_data + i)->cyl = cyl;
+                        (ct_data + i)->head = head;
+                        (ct_data + i)->record = i + 1;
+                        (ct_data + i)->kl = 0;
+                        (ct_data + i)->dl = bs;
+                        last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+                        last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+                        last_ccw->count = 8;
+                        last_ccw->cda = (__u32) __pa (ct_data + i);
+                        last_ccw ++;
+                }
+                (last_ccw-1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
+                fcp->device = device;
+                atomic_set(&fcp->status,CQR_STATUS_FILLED);
+        }
+	return fcp;
 }
 
 static dasd_era_t
@@ -781,8 +737,9 @@
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
 		return dasd_era_none;
         
-	switch (device->devinfo.sid_data.cu_model) {
+	switch (device->devinfo.sid_data.cu_type) {
 	case 0x3990:
+	case 0x2105:
 		return dasd_3990_erp_examine (cqr, stat);
 	case 0x9343:
 		return dasd_9343_erp_examine (cqr, stat);
@@ -838,20 +795,20 @@
 	/* count bhs to prevent errors, when bh smaller than block */
 	bhct = 0;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
+                if (bh->b_size > byt_per_blk)
+                        for (size = 0; size < bh->b_size; size += byt_per_blk)
 				bhct++;
 		else
 			bhct++;
 	}
-
+        
 	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
                                    2 + bhct,
-			     sizeof (DE_eckd_data_t) +
-			     sizeof (LO_eckd_data_t));
-        if ( ! rw_cp ) {
-          return NULL;
-        }
+                                   sizeof (DE_eckd_data_t) +
+                                   sizeof (LO_eckd_data_t));
+	if (!rw_cp) {
+		return NULL;
+	}
 	DE_data = rw_cp->data;
 	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
 	ccw = rw_cp->cpaddr;
@@ -860,17 +817,17 @@
 	ccw->flags = CCW_FLAG_CC;
 	ccw++;
 	locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
-		       req->nr_sectors >> shift, rw_cmd, device);
+		       req->nr_sectors >> shift, rw_cmd, device,device->sizes.bp_block);
 	ccw->flags = CCW_FLAG_CC;
 	for (bh = req->bh; bh != NULL;) {
 		if (bh->b_size > byt_per_blk) {
-		for (size = 0; size < bh->b_size; size += byt_per_blk) {
-                        ccw++;
-                        ccw->flags = CCW_FLAG_CC;
-                        ccw->cmd_code = rw_cmd;
-                        ccw->count = byt_per_blk;
-				ccw->cda = (void *) __pa (bh->b_data + size);
-		}
+			for (size = 0; size < bh->b_size; size += byt_per_blk) {
+				ccw++;
+				ccw->flags = CCW_FLAG_CC;
+				ccw->cmd_code = rw_cmd;
+				ccw->count = byt_per_blk;
+				ccw->cda = (__u32) __pa (bh->b_data + size);
+			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
 			for (size = 0; bh != NULL && size < byt_per_blk;) {
@@ -878,22 +835,23 @@
 				ccw->flags = CCW_FLAG_DC;
 				ccw->cmd_code = rw_cmd;
 				ccw->count = bh->b_size;
-				ccw->cda = (void *) __pa (bh->b_data);
+				ccw->cda = (__u32) __pa (bh->b_data);
 				size += bh->b_size;
 				bh = bh->b_reqnext;
-	}
+			}
 			if (size != byt_per_blk) {
-				PRINT_WARN ("Cannot fulfill small request %d vs. %d (%d sects)\n", size, byt_per_blk, req->nr_sectors);
+				PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors);
 				ccw_free_request (rw_cp);
-		return NULL;
-	}
+				return NULL;
+			}
 			ccw->flags = CCW_FLAG_CC;
 		}
 	}
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
         rw_cp->device = device;
-        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->expires = 60 * (unsigned long long)0xf4240000; /* 60 seconds */
         rw_cp->req = req;
+        rw_cp->retries = 2;
         atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
 	return rw_cp;
 }
@@ -924,7 +882,7 @@
                         for (sct = 0; sct < 8; sct++) {
                                 len += sprintf ( page + len," %2d:0x%02x",
                                                  8 * sl + sct, sense[8 * sl + sct]);
-        }
+                        }
                         len += sprintf ( page + len,"\n");
                 }
                 if (sense[27] & 0x80) {	
@@ -938,8 +896,8 @@
                         len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
                                          "32 Byte: Format: %x Exception class %x\n",
                                          sense[6] & 0x0f, sense[22] >> 4);
-		}
-	}
+                }
+        }
         return page;
 }
 
@@ -964,11 +922,43 @@
 int
 dasd_eckd_init( void ) {
         int rc = 0;
+	int i;
         printk ( KERN_INFO PRINTK_HEADER
                  "%s discipline initializing\n", dasd_eckd_discipline.name);
         ASCEBC(dasd_eckd_discipline.ebcname,4);
         dasd_discipline_enq(&dasd_eckd_discipline);
-        
+#ifdef CONFIG_DASD_DYNAMIC
+        for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
+		printk (KERN_INFO PRINTK_HEADER
+			"We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+			dasd_eckd_known_devices[i].ci.hc.ctype,
+			dasd_eckd_known_devices[i].ci.hc.cmode,
+			dasd_eckd_known_devices[i].ci.hc.dtype,
+			dasd_eckd_known_devices[i].ci.hc.dmode);
+		s390_device_register(&dasd_eckd_known_devices[i]);
+	} 
+#endif /* CONFIG_DASD_DYNAMIC */
+        return rc;
+}
+
+void
+dasd_eckd_cleanup( void ) {
+        int rc = 0;
+	int i;
+        printk ( KERN_INFO PRINTK_HEADER
+                 "%s discipline cleaning up\n", dasd_eckd_discipline.name);
+#ifdef CONFIG_DASD_DYNAMIC
+        for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
+		printk (KERN_INFO PRINTK_HEADER
+			"We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+			dasd_eckd_known_devices[i].ci.hc.ctype,
+			dasd_eckd_known_devices[i].ci.hc.cmode,
+			dasd_eckd_known_devices[i].ci.hc.dtype,
+			dasd_eckd_known_devices[i].ci.hc.dmode);
+		s390_device_register(&dasd_eckd_known_devices[i]);
+	} 
+#endif /* CONFIG_DASD_DYNAMIC */
+        dasd_discipline_deq(&dasd_eckd_discipline);
         return rc;
 }
 
diff -urN linux-2.2.18-pre20/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
--- linux-2.2.18-pre20/drivers/s390/block/dasd_fba.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/block/dasd_fba.c	Mon Dec  3 22:14:17 2001
@@ -18,6 +18,7 @@
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/s390dyn.h>
 
 #include "dasd.h"
 #include "dasd_fba.h"
@@ -40,6 +41,20 @@
         dasd_fba_characteristics_t rdc_data;
 } dasd_fba_private_t;
 
+static
+devreg_t dasd_fba_known_devices[] = {
+        {
+                ci : { hc: { ctype: 0x6310, dtype: 0x9336 } },
+                flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+                oper_func: dasd_oper_handler
+        },
+        {
+                ci : { hc: { ctype: 0x3880, dtype: 0x3370 } },
+                flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+                oper_func: dasd_oper_handler
+        }
+};
+
 static inline void
 define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
 	       int blksize, int beg, int nr)
@@ -86,7 +101,7 @@
                         return 0;
         if ( info->sid_data.cu_type == 0x6310 )
                 if ( info->sid_data.dev_type == 0x9336 )
-	return 0;
+                        return 0;
         return -ENODEV;
 }
 
@@ -247,17 +262,17 @@
 	/* count bhs to prevent errors, when bh smaller than block */
 	bhct = 0;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
+                if (bh->b_size > byt_per_blk)
+                        for (size = 0; size < bh->b_size; size += byt_per_blk)
 				bhct++;
 		else
 			bhct++;
 	}
-
+        
 	rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
                                    2 + bhct,
-			     sizeof (DE_fba_data_t) +
-			     sizeof (LO_fba_data_t));
+                                   sizeof (DE_fba_data_t) +
+                                   sizeof (LO_fba_data_t));
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -326,7 +341,7 @@
         int len;
         if ( page == NULL ) {
                 return NULL;
-}
+        }
 
         len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
                         "device %04X on irq %d: I/O status report:\n",
@@ -352,15 +367,48 @@
         int_handler:                    dasd_int_handler            
 };
 
+
 int
 dasd_fba_init( void ) {
-	int rc = 0;
+        int rc = 0;
+	int i;
         printk ( KERN_INFO PRINTK_HEADER
                  "%s discipline initializing\n", dasd_fba_discipline.name);
         ASCEBC(dasd_fba_discipline.ebcname,4);
         dasd_discipline_enq(&dasd_fba_discipline);
+#ifdef CONFIG_DASD_DYNAMIC
+        for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
+                printk (KERN_INFO PRINTK_HEADER
+                        "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+                        dasd_fba_known_devices[i].ci.hc.ctype,
+                        dasd_fba_known_devices[i].ci.hc.cmode,
+                        dasd_fba_known_devices[i].ci.hc.dtype,
+                        dasd_fba_known_devices[i].ci.hc.dmode);
+                s390_device_register(&dasd_fba_known_devices[i]);
+        }
+#endif /* CONFIG_DASD_DYNAMIC */
+        return rc;
+}
 
-	return rc;
+void
+dasd_fba_cleanup( void ) {
+        int rc = 0;
+	int i;
+        printk ( KERN_INFO PRINTK_HEADER
+                 "%s discipline cleaning up\n", dasd_fba_discipline.name);
+#ifdef CONFIG_DASD_DYNAMIC
+        for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
+                printk (KERN_INFO PRINTK_HEADER
+                        "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+                        dasd_fba_known_devices[i].ci.hc.ctype,
+                        dasd_fba_known_devices[i].ci.hc.cmode,
+                        dasd_fba_known_devices[i].ci.hc.dtype,
+                        dasd_fba_known_devices[i].ci.hc.dmode);
+                s390_device_register(&dasd_fba_known_devices[i]);
+        }
+#endif /* CONFIG_DASD_DYNAMIC */
+        dasd_discipline_deq(&dasd_fba_discipline);
+        return rc;
 }
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.2.18-pre20/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- linux-2.2.18-pre20/drivers/s390/block/xpram.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/xpram.c	Mon Dec  3 22:14:17 2001
@@ -989,7 +989,7 @@
  fail_malloc:
 	read_ahead[major] = 0;
 	blk_dev[major].request_fn = NULL;
-	unregister_chrdev(major, "xpram");
+	unregister_blkdev(major, "xpram");
 	return result;
 }
 
diff -urN linux-2.2.18-pre20/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c
--- linux-2.2.18-pre20/drivers/s390/ccwcache.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/ccwcache.c	Mon Dec  3 22:14:17 2001
@@ -1,5 +1,5 @@
 /* 
-   * File...........: linux/drivers/s390/block/ccwcache.c
+   * File...........: linux/drivers/s390/ccwcache.c
    * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
    * Bugreports.to..: <Linux390@de.ibm.com>
    * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
@@ -15,7 +15,6 @@
 #include <asm/ebcdic.h>
 #include <asm/spinlock.h>
 
-
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif
@@ -33,6 +32,7 @@
 
 /* pointer to list of allocated requests */
 static ccw_req_t *ccwreq_actual = NULL;
+static spinlock_t ccwchain_lock = SPIN_LOCK_UNLOCKED;
 
 /* pointer to debug area */
 static debug_info_t *debug_area = NULL;
@@ -56,12 +56,16 @@
 static void 
 dechain ( ccw_req_t *request )
 {
+	long flags;
+
 	/* Sanity checks */
 	if ( request == NULL ) {
 		printk( KERN_WARNING PRINTK_HEADER
 			"Trying to deallocate NULL request\n");
 		return;
 	}
+
+	spin_lock_irqsave(&ccwchain_lock,flags);
 	/* first deallocate request from list of allocates requests */
 	if ( request -> int_next && request -> int_prev ) {
 		if ( request -> int_next == request -> int_prev ) {
@@ -75,6 +79,7 @@
 		}
 	} else if ( request -> int_next || request -> int_prev ) {
 	}
+	spin_unlock_irqrestore(&ccwchain_lock,flags);
 	return;
 }
 
@@ -90,13 +95,14 @@
 	ccw_req_t * request = NULL;
 	int cachind = 0;
 	int size_needed = 0;
+	long flags;
 
 	debug_text_event ( debug_area, 1, "ALLC");
 	if ( magic ) {
 		debug_text_event ( debug_area, 1, magic);
 	}
-	debug_event ( debug_area, 1, cplength);
-	debug_event ( debug_area, 1, datasize);
+	debug_int_event ( debug_area, 1, cplength);
+	debug_int_event ( debug_area, 1, datasize);
 
 	/* Sanity checks */
 	if ( cplength == 0 ) {
@@ -140,7 +146,7 @@
 	/* Try to fulfill the request from a cache */
 	while (  cachind < CCW_NUMBER_CACHES ) { /* Now try to get an entry from a cache above or equal to cachind */
 	  if ( ccw_cache[cachind] == NULL ){
-	    printk("cache=%p index %d\n",cachind,cachind);
+	    printk(KERN_WARNING PRINTK_HEADER "NULL cache found! cache=%p index %d\n",ccw_cache[cachind],cachind);
 	  }
 	  request = kmem_cache_alloc ( ccw_cache[cachind], GFP_ATOMIC );
 	  if ( request != NULL ) {
@@ -148,13 +154,13 @@
 	    request->cache = ccw_cache[cachind];
 	    break;
 	  } else {
-	    printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache");
+	    printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache\n");
 	  }
  	  cachind++;
 	} 
 	/* if no success, fall back to kmalloc */
 	if ( request == NULL ) {
-	  printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc");
+	  printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc\n");
 		request = kmalloc ( sizeof(ccw_req_t), GFP_ATOMIC );
 		if ( request != NULL ) {
 			memset ( request, 0, sizeof(ccw_req_t));
@@ -162,7 +168,7 @@
 	}
 	/* Initialize request */
 	if ( request == NULL ) {  
-		printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request");
+		printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request\n");
 	} else {
 		if ( request -> cache != NULL ) {
 			/* Three cases when coming from a cache */
@@ -215,6 +221,7 @@
 		request -> cplength = cplength;
 		request -> datasize = datasize;
 		/* enqueue request to list of allocated requests */
+		spin_lock_irqsave(&ccwchain_lock,flags);
 		if ( ccwreq_actual == NULL ) { /* queue empty */
 			ccwreq_actual = request;
 			request->int_prev = ccwreq_actual;
@@ -225,8 +232,9 @@
 			request->int_prev->int_next = request;
 			request->int_next->int_prev = request;
 		}
+		spin_unlock_irqrestore(&ccwchain_lock,flags);
 	}
-	debug_event ( debug_area, 1, (long)request);
+	debug_int_event ( debug_area, 1, (long)request);
 	return request;
 }
 
@@ -242,7 +250,7 @@
 	int slabsize;
 
 	debug_text_event ( debug_area, 1, "FREE");
-	debug_event ( debug_area, 1, (long)request);
+	debug_int_event ( debug_area, 1, (long)request);
 	/* Sanity checks */
 	if ( request == NULL ) {
 		printk(KERN_DEBUG PRINTK_HEADER"Trying to deallocate NULL request\n");
@@ -256,7 +264,7 @@
 		if ( request ->cpaddr ) {
 			kfree ( request -> cpaddr );
 		}
-		dechain ( request);
+		dechain (request);
 		kfree ( request );
 	} else {
 		/* Find which area has been allocated by kmalloc */
@@ -300,26 +308,28 @@
 	int cachind;
 
 	/* allocate a debug area */
-	debug_area = debug_register( "ccwcache", 2, 4);
+	debug_area = debug_register( "ccwcache", 2, 4,4);
 	if ( ! debug_area ) {
 		printk ( KERN_WARNING PRINTK_HEADER"cannot allocate debug area\n" );
 	} else {
 		printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area );
 	}
+        debug_register_view(debug_area,&debug_hex_view);
+        debug_register_view(debug_area,&debug_ebcdic_view);
 	debug_text_event ( debug_area, 0, "INIT");
 	
 	/* First allocate the kmem caches */
 	for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
 		int slabsize = SMALLEST_SLAB << cachind;
 		debug_text_event ( debug_area, 1, "allc");
-		debug_event ( debug_area, 1, slabsize);
+		debug_int_event ( debug_area, 1, slabsize);
 		sprintf ( ccw_cache_name[cachind], 
 			  "%s%d%c", ccw_name_template, slabsize, 0);
 		ccw_cache[cachind] = kmem_cache_create( ccw_cache_name[cachind], 
 							slabsize, 0,
 							SLAB_HWCACHE_ALIGN, 
 							NULL, NULL );
-		debug_event ( debug_area, 1, (long)ccw_cache[cachind]);
+		debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]);
 		if ( ! ccw_cache [cachind] ) {
 			printk (KERN_WARNING PRINTK_HEADER "Allocation of CCW cache failed\n");
 		}
@@ -345,7 +355,7 @@
 			}
 		}
 	}
-	debug_unregister( debug_area ,"ccwcache");
+	debug_unregister( debug_area );
 }
 
 #ifdef MODULE
diff -urN linux-2.2.18-pre20/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
--- linux-2.2.18-pre20/drivers/s390/char/con3215.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/char/con3215.c	Mon Dec  3 22:14:17 2001
@@ -5,6 +5,10 @@
  *  S390 version
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ *  Updated:
+ *   Aug-2000: Added tab support
+ *             Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu)
  */
 
 #include <linux/config.h>
@@ -45,6 +49,8 @@
 #define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */
 #define RAW3215_BH_PENDING  256       /* indication for bh scheduling */
 
+#define TAB_STOP_SIZE	    8         /* tab stop size */
+
 struct _raw3215_info;		      /* forward declaration ... */
 
 int raw3215_condevice = -1;           /* preset console device */
@@ -87,6 +93,7 @@
 	char *message;                /* pending message from raw3215_irq */
 	int msg_dstat;                /* dstat for pending message */
 	int msg_cstat;                /* cstat for pending message */
+	int line_pos;		      /* position on the line (for tabs) */
 } raw3215_info;
 
 static raw3215_info *raw3215[NR_3215];	/* array of 3215 devices structures */
@@ -103,6 +110,8 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
+extern void tod_wait(unsigned long usecs);
+
 __initfunc(void con3215_setup(char *str, char *ints))
 {
         int vdev;
@@ -167,7 +176,7 @@
         ccw->cmd_code = 0x0A; /* read inquiry */
         ccw->flags = 0x20;    /* ignore incorrect length */
         ccw->count = 160;
-        ccw->cda = (void *) virt_to_phys(raw->inbuf);
+        ccw->cda = (__u32) __pa(raw->inbuf);
 }
 
 /*
@@ -178,7 +187,7 @@
  */
 static void raw3215_mk_write_req(raw3215_info *raw)
 {
-	raw3215_req *req;
+        raw3215_req *req;
 	ccw1_t *ccw;
 	int len, count, ix, lines;
 
@@ -186,28 +195,28 @@
                 return;
         /* check if there is a queued write request */
         req = raw->queued_write;
-	if (req == NULL) {
+        if (req == NULL) {
                 /* no queued write request, use new req structure */
-		req = raw3215_alloc_req();
+                req = raw3215_alloc_req();
                 req->type = RAW3215_WRITE;
-		req->info = raw;
+                req->info = raw;
                 raw->queued_write = req;
         } else {
                 raw->written -= req->len;
-}
+        }
 
 	ccw = req->ccws;
         req->start = (raw->head - raw->count + raw->written) &
                      (RAW3215_BUFFER_SIZE - 1);
-/*
+        /*
          * now we have to count newlines. We can at max accept
          * RAW3215_MAX_NEWLINE newlines in a single ssch due to
          * a restriction in VM
- */
+         */
         lines = 0;
         ix = req->start;
         while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) {
-                if (raw->buffer[ix] == '\n')
+                if (raw->buffer[ix] == 0x15)
                         lines++;
                 ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
         }
@@ -226,21 +235,20 @@
 			ccw[-1].flags |= 0x40; /* use command chaining */
 		ccw->cmd_code = 0x01; /* write, auto carrier return */
 		ccw->flags = 0x20;    /* ignore incorrect length ind.  */
-		ccw->cda =
-			(void *) virt_to_phys(raw->buffer + ix);
+		ccw->cda = (__u32) __pa(raw->buffer + ix);
 		count = len;
 		if (ix + count > RAW3215_BUFFER_SIZE)
-			count = RAW3215_BUFFER_SIZE-ix;
+			count = RAW3215_BUFFER_SIZE - ix;
 		ccw->count = count;
 		len -= count;
 		ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
 		ccw++;
 	}
-/*
+        /*
          * Add a NOP to the channel program. 3215 devices are purely
          * emulated and its much better to avoid the channel end 
          * interrupt in this case.
- */
+         */
         if (ccw > req->ccws)
                 ccw[-1].flags |= 0x40; /* use command chaining */
         ccw->cmd_code = 0x03; /* NOP */
@@ -319,7 +327,7 @@
 		if ((raw->queued_write->delayable == 0) ||
 		    (raw->flags & RAW3215_FLUSHING)) {
 			/* execute write requests bigger than minimum size */
-			raw3215_start_io(raw);
+                        raw3215_start_io(raw);
 			if (raw->flags & RAW3215_TIMER_RUNS) {
 				del_timer(&raw->timer);
 				raw->flags &= ~RAW3215_TIMER_RUNS;
@@ -459,7 +467,7 @@
                         return;              /* That shouldn't happen ... */
 		if (req->type == RAW3215_READ && raw->tty != NULL) {
 			tty = raw->tty;
-			count = 160 - req->residual;
+                        count = 160 - req->residual;
                         if (MACHINE_IS_P390) {
                                 slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
                                 if (count > slen)
@@ -517,7 +525,7 @@
 		} else if (req->type == RAW3215_WRITE) {
 			raw->count -= req->len;
                         raw->written -= req->len;
-		}
+		} 
 		raw->flags &= ~RAW3215_WORKING;
 		raw3215_free_req(req);
 		/* check for empty wait */
@@ -530,7 +538,7 @@
                 raw3215_sched_bh(raw);
 		break;
 	default:
-			/* Strange interrupt, I'll do my best to clean up */
+		/* Strange interrupt, I'll do my best to clean up */
                 if ((raw = raw3215_find_info(irq)) == NULL)
                         return;              /* That shouldn't happen ... */
 		if (req != NULL && req->type != RAW3215_FREE) {
@@ -540,18 +548,46 @@
                         }
                         raw->flags &= ~RAW3215_WORKING;
                         raw3215_free_req(req);
-			}
-			raw->message = KERN_WARNING
-				"Spurious interrupt in in raw3215_irq "
-				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
-			raw->msg_dstat = dstat;
-			raw->msg_cstat = cstat;
+		}
+		raw->message = KERN_WARNING
+			"Spurious interrupt in in raw3215_irq "
+			"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
+		raw->msg_dstat = dstat;
+		raw->msg_cstat = cstat;
                 raw3215_sched_bh(raw);
 	}
 	return;
 }
 
 /*
+ * Wait until length bytes are available int the output buffer.
+ * Has to be called with the s390irq lock held. Can be called
+ * disabled.
+ */
+void raw3215_make_room(raw3215_info *raw, unsigned int length)
+{
+	while (RAW3215_BUFFER_SIZE - raw->count < length) {
+		/* there might be a request pending */
+		raw->flags |= RAW3215_FLUSHING;
+		raw3215_mk_write_req(raw);
+		raw3215_try_io(raw);
+		raw->flags &= ~RAW3215_FLUSHING;
+		if (wait_cons_dev(raw->irq) != 0) {
+			/* that shouldn't happen */
+			raw->count = 0;
+			raw->written = 0;
+		}
+		/* Enough room freed up ? */
+		if (RAW3215_BUFFER_SIZE - raw->count >= length)
+			break;
+		/* there might be another cpu waiting for the lock */
+		s390irq_spin_unlock(raw->irq);
+		tod_wait(100);
+		s390irq_spin_lock(raw->irq);
+	}
+}
+
+/*
  * String write routine for 3215 devices
  */
 static int
@@ -569,16 +605,7 @@
 					     RAW3215_BUFFER_SIZE : length;
 		length -= count;
 
-		while (RAW3215_BUFFER_SIZE - raw->count < count) {
-			/* there might be a request pending */
-                        raw3215_mk_write_req(raw);
-			raw3215_try_io(raw);
-			if (wait_cons_dev(raw->irq) != 0) {
-				/* that shouldn't happen */
-				raw->count = 0;
-                                raw->written = 0;
-			} 
-		}
+                raw3215_make_room(raw, count);
 
 		/* copy string to output buffer and convert it to EBCDIC */
 		if (from_user) {
@@ -599,6 +626,7 @@
 				raw->head = (raw->head + c) &
 					    (RAW3215_BUFFER_SIZE - 1);
 				raw->count += c;
+				raw->line_pos += c;
 				str += c;
 				count -= c;
 				ret += c;
@@ -615,6 +643,7 @@
 				raw->head = (raw->head + c) &
 					    (RAW3215_BUFFER_SIZE - 1);
 				raw->count += c;
+				raw->line_pos += c;
 				str += c;
 				count -= c;
 				ret += c;
@@ -622,8 +651,8 @@
 		}
                 if (!(raw->flags & RAW3215_WORKING)) {
                         raw3215_mk_write_req(raw);
-		/* start or queue request */
-		raw3215_try_io(raw);
+		        /* start or queue request */
+		        raw3215_try_io(raw);
                 }
 		s390irq_spin_unlock_irqrestore(raw->irq, flags);
 	}
@@ -634,29 +663,35 @@
 /*
  * Put character routine for 3215 devices
  */
+	
 static void raw3215_putchar(raw3215_info *raw, unsigned char ch)
 {
 	unsigned long flags;
+        unsigned int length, i;
 
 	s390irq_spin_lock_irqsave(raw->irq, flags);
-	while (RAW3215_BUFFER_SIZE - raw->count < 1) {
-		/* there might be a request pending */
-                raw3215_mk_write_req(raw);
-		raw3215_try_io(raw);
-		if (wait_cons_dev(raw->irq) != 0) {
-			/* that shouldn't happen */
-			raw->count = 0;
-                        raw->written = 0;
-		}
+	if (ch == '\t') {
+		length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE);
+		raw->line_pos += length;
+		ch = ' ';
+        } else if (ch == '\n') {
+		length = 1;
+		raw->line_pos = 0;
+	} else {
+		length = 1;
+		raw->line_pos++;
 	}
+        raw3215_make_room(raw, length);
 
-	raw->buffer[raw->head] = (char) _ascebc[(int) ch];
-	raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
-	raw->count++;
+	for (i = 0; i < length; i++) {
+		raw->buffer[raw->head] = (char) _ascebc[(int) ch];
+		raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
+		raw->count++;
+	}
         if (!(raw->flags & RAW3215_WORKING)) {
                 raw3215_mk_write_req(raw);
-	/* start or queue request */
-	raw3215_try_io(raw);
+	        /* start or queue request */
+	        raw3215_try_io(raw);
         }
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 }
@@ -690,6 +725,7 @@
 	if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
 			"3215 terminal driver", &raw->devstat) != 0)
 		return -1;
+	raw->line_pos = 0;
 	raw->flags |= RAW3215_ACTIVE;
 	s390irq_spin_lock_irqsave(raw->irq, flags);
         set_cons_dev(raw->irq);
@@ -739,12 +775,12 @@
         while (count <= number && irq != -ENODEV) {
                 if (get_dev_info(irq, &dinfo) == -ENODEV)
                         break;
-		if (dinfo.devno == raw3215_condevice ||
+                if (dinfo.devno == raw3215_condevice ||
                     dinfo.sid_data.cu_type == 0x3215) {
-			count++;
+                        count++;
                     if (count > number)
-	return irq;
-}
+                        return irq;
+                }
                 irq = get_irq_next(irq);
         }
         return -1;            /* console not found */
@@ -762,7 +798,8 @@
         if (!MACHINE_IS_VM && !MACHINE_IS_P390)
                 return 0;
 	raw = raw3215[0];  /* 3215 console is the first one */
-	if (raw->irq == -1) /* now console device found in con3215_init */
+	if (raw == NULL || raw->irq == -1)
+                /* console device not found in con3215_init */
 		return -1;
 	return raw3215_startup(raw);
 }
@@ -774,11 +811,24 @@
 con3215_write(struct console *co, const char *str, unsigned int count)
 {
 	raw3215_info *raw;
+	int i;
 
 	if (count <= 0)
 		return;
-	raw = raw3215[0];  /* console 3215 is the first one */
-	raw3215_write(raw, str, 0, count);
+        raw = raw3215[0];       /* console 3215 is the first one */
+        while (count > 0) {
+                for (i = 0; i < count; i++)
+                        if (str[i] == '\t' || str[i] == '\n')
+                                break;
+                raw3215_write(raw, str, 0, i);
+		count -= i;
+		str += i;
+                if (count > 0) {
+			raw3215_putchar(raw, *str);
+			count--;
+			str++;
+                }
+        }
 }
 
 kdev_t con3215_device(struct console *c)
@@ -797,17 +847,7 @@
 
 	raw = raw3215[0];  /* console 3215 is the first one */
 	s390irq_spin_lock_irqsave(raw->irq, flags);
-	while (raw->count > 0) {
-		/* there might be a request pending */
-		raw->flags |= RAW3215_FLUSHING;
-		raw3215_try_io(raw);
-		if (wait_cons_dev(raw->irq) != 0) {
-			/* that shouldn't happen */
-			raw->count = 0;
-                        raw->written = 0;
-		}
-		raw->flags &= ~RAW3215_FLUSHING;
-	}
+	raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 }
 
@@ -914,7 +954,12 @@
 	raw3215_info *raw;
 				
 	raw = (raw3215_info *) tty->driver_data;
-	return RAW3215_BUFFER_SIZE - raw->count;
+
+	/* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */
+	if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0)
+		return RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE;
+	else
+		return 0;
 }
 
 /*
@@ -924,7 +969,7 @@
 		    const unsigned char *buf, int count)
 {
 	raw3215_info *raw;
-	int ret;
+	int ret = 0;
 				
 	if (!tty)
 		return 0;
@@ -1062,8 +1107,8 @@
 	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
                 return kmem_start;
         if (MACHINE_IS_VM) {
-	cpcmd("TERM CONMODE 3215", NULL, 0);
-	cpcmd("TERM AUTOCR OFF", NULL, 0);
+	        cpcmd("TERM CONMODE 3215", NULL, 0);
+	        cpcmd("TERM AUTOCR OFF", NULL, 0);
         }
 
 	kmem_start = (kmem_start + 7) & -8L;
diff -urN linux-2.2.18-pre20/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h
--- linux-2.2.18-pre20/drivers/s390/char/hwc.h	Wed May  3 17:16:43 2000
+++ linux/drivers/s390/char/hwc.h	Mon Dec  3 22:14:17 2001
@@ -1,13 +1,13 @@
 /*
  *  drivers/s390/char/hwc.h
- *
+ * 
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
  *
- *
- *
+ * 
+ * 
  */
 
 #ifndef __HWC_H__
@@ -109,29 +109,29 @@
 
 go_t;
 
-typedef	struct {
-	go_t	go;
+typedef struct {
+	go_t go;
 } __attribute__ ((packed)) 
 
 mdb_body_t;
 
 typedef struct {
 	_MDB_HEADER
-	mdb_body_t	mdb_body;
+	mdb_body_t mdb_body;
 } __attribute__ ((packed)) 
 
 mdb_t;
 
 typedef struct {
 	_EBUF_HEADER
-	mdb_t		mdb;
+	mdb_t mdb;
 } __attribute__ ((packed)) 
 
 msgbuf_t;
 
 typedef struct {
 	_HWCB_HEADER
-	msgbuf_t	msgbuf;
+	msgbuf_t msgbuf;
 } __attribute__ ((packed)) 
 
 write_hwcb_t;
@@ -144,27 +144,27 @@
 
 static write_hwcb_t write_hwcb_template =
 {
-	sizeof(write_hwcb_t),				
-	0x00,						
+	sizeof (write_hwcb_t),
+	0x00,
 	{
 		0x00,
-		0x00,					
-		0x00					
+		0x00,
+		0x00
 	},
-	0x0000,						
-	{ 	
-		sizeof(msgbuf_t),			
-		ET_Msg,				
-		0x00,					
-		0x0000,					
-		{ 	
-			sizeof(mdb_t),			
+	0x0000,
+	{
+		sizeof (msgbuf_t),
+		ET_Msg,
+		0x00,
+		0x0000,
+		{
+			sizeof (mdb_t),
 			0x0001,
 			0xD4C4C240,
 			0x00000001,
-			{ 	
-				{ 	
-					sizeof(go_t),	
+			{
+				{
+					sizeof (go_t),
 					0x0001
 
 				}
@@ -175,38 +175,38 @@
 
 static mto_t mto_template =
 {
-	sizeof(mto_t),
+	sizeof (mto_t),
 	0x0004,
-	LTF_EndText,	
-	0x00			
+	LTF_EndText,
+	0x00
 };
 
 typedef u32 _hwcb_mask_t;
 
 typedef struct {
 	_HWCB_HEADER
-	u16		_reserved;
-	u16		mask_length;
-	_hwcb_mask_t	cp_receive_mask;
-	_hwcb_mask_t	cp_send_mask;
-	_hwcb_mask_t	hwc_receive_mask;
-	_hwcb_mask_t	hwc_send_mask;
+	u16 _reserved;
+	u16 mask_length;
+	_hwcb_mask_t cp_receive_mask;
+	_hwcb_mask_t cp_send_mask;
+	_hwcb_mask_t hwc_receive_mask;
+	_hwcb_mask_t hwc_send_mask;
 } __attribute__ ((packed)) 
 
 init_hwcb_t;
 
 static init_hwcb_t init_hwcb_template =
 {
-	sizeof(init_hwcb_t),
+	sizeof (init_hwcb_t),
 	0x00,
 	{
 		0x00,
-		0x00,				
-		0x00				
+		0x00,
+		0x00
 	},
-	0x0000,					
-	0x0000,					
-	sizeof(_hwcb_mask_t),
+	0x0000,
+	0x0000,
+	sizeof (_hwcb_mask_t),
 	ET_OpCmd_Mask | ET_PMsgCmd_Mask,
 	ET_Msg_Mask
 };
@@ -238,12 +238,12 @@
 static read_hwcb_t read_hwcb_template =
 {
 	PAGE_SIZE,
-	0x00,		
+	0x00,
 	{
-		0x00,	
-		0x00,	
-		0x80	
+		0x00,
+		0x00,
+		0x80
 	}
 };
 
-#endif   /* __HWC_H__ */ 
+#endif				/* __HWC_H__ */
diff -urN linux-2.2.18-pre20/drivers/s390/char/hwc_con.c linux/drivers/s390/char/hwc_con.c
--- linux-2.2.18-pre20/drivers/s390/char/hwc_con.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/char/hwc_con.c	Mon Dec  3 22:14:17 2001
@@ -18,16 +18,16 @@
 
 #include "hwc_rw.h"
 
-extern void hwc_tty_init(void);
+extern void hwc_tty_init (void);
 
 #ifdef CONFIG_HWC_CONSOLE
 
-#define  hwc_console_major 4 
+#define  hwc_console_major 4
 #define  hwc_console_minor 0
-#define  hwc_console_name  "console" 
+#define  hwc_console_name  "console"
 
-void hwc_console_write(struct console *, const char *, unsigned int);
-kdev_t hwc_console_device(struct console *);
+void hwc_console_write (struct console *, const char *, unsigned int);
+kdev_t hwc_console_device (struct console *);
 void hwc_console_unblank (void);
 
 #define  HWC_CON_PRINT_HEADER "hwc console driver: "
@@ -39,36 +39,36 @@
 	hwc_console_write,
 	NULL,
 	hwc_console_device,
-	NULL,			
+	NULL,
 	hwc_console_unblank,
-	NULL,			
+	NULL,
 	CON_PRINTBUFFER,
 	0,
 	0,
 	NULL
 };
- 
+
 void 
 hwc_console_write (
-	struct console *console,
-	const char *message,
-	unsigned int count)
+			  struct console *console,
+			  const char *message,
+			  unsigned int count)
 {
 
 	if (console->device (console) != hwc_console.device (&hwc_console)) {
 
-		hwc_printk(KERN_WARNING HWC_CON_PRINT_HEADER
-				"hwc_console_write() called with wrong "
-				"device number");
+		hwc_printk (KERN_WARNING HWC_CON_PRINT_HEADER
+			    "hwc_console_write() called with wrong "
+			    "device number");
 		return;
 	}
-	hwc_write(0, message, count);
+	hwc_write (0, message, count);
 }
 
 kdev_t 
 hwc_console_device (struct console * c)
 {
-	return  MKDEV(hwc_console_major, hwc_console_minor);
+	return MKDEV (hwc_console_major, hwc_console_minor);
 }
 
 void 
@@ -77,26 +77,26 @@
 	hwc_unblank ();
 }
 
-#endif	
+#endif
 
-__initfunc(unsigned long hwc_console_init(unsigned long kmem_start))
+__initfunc (unsigned long hwc_console_init (unsigned long kmem_start))
 {
 
 #ifdef CONFIG_3215
-        if (MACHINE_IS_VM)
-                return kmem_start;
+	if (MACHINE_IS_VM)
+		return kmem_start;
 #endif
 	if (MACHINE_IS_P390)
 		return kmem_start;
 
-	if (hwc_init(&kmem_start) == 0) {
+	if (hwc_init (&kmem_start) == 0) {
 
 		hwc_tty_init ();
 
 #ifdef CONFIG_HWC_CONSOLE
 
-		register_console(&hwc_console);
-#endif	
+		register_console (&hwc_console);
+#endif
 	} else
 		panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !");
 
diff -urN linux-2.2.18-pre20/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
--- linux-2.2.18-pre20/drivers/s390/char/hwc_rw.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/char/hwc_rw.c	Mon Dec  3 22:14:17 2001
@@ -6,11 +6,11 @@
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
  *
+ * 
  *
- *
- *
- *
- *
+ * 
+ * 
+ * 
  */
 
 #include <linux/kernel.h>
@@ -50,6 +50,8 @@
 
 #undef BUFFER_STRESS_TEST
 
+#define MEASURE_HWC_OUTPUT
+
 typedef struct {
 	unsigned char *next;
 	unsigned short int mto_char_sum;
@@ -115,7 +117,7 @@
 static unsigned char _obuf[MAX_HWCB_ROOM];
 
 static unsigned char
-	_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+ _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
 
 typedef u32 kmem_pages_t;
 
@@ -179,39 +181,42 @@
 {
 	{
 	},
-	{		
-		8,		
-		0,		
-		80,		
-		CODE_ASCII,	
-		1,		
-		50,		
-		MAX_KMEM_PAGES,	
-
-		0,		
-
-		0x6c		
-
+	{
+		8,
+		    0,
+		    80,
+		    CODE_ASCII,
+		    1,
+		    50,
+		    MAX_KMEM_PAGES,
+
+		    0,
+
+		    0x6c,
+
+		    0,
+		    0,
+		    0
 	},
-	NULL,		
-	NULL,		
-	0,		
-	0,		
-	0,		
-	0,		
-	0,		
-	0,		
-	_obuf,		
-	0,		
-	0,		
-	0,		
-	_page,		
-	0,		
-	NULL,		
-	0,		
-	0,		
-	0,		
-	0,		
+	    NULL,
+	    NULL,
+	    0,
+	    0,
+	    0,
+	    0,
+	    0,
+	    0,
+	    _obuf,
+	    0,
+	    0,
+	    0,
+	    _page,
+	    0,
+	    NULL,
+	    0,
+	    0,
+	    0,
+	    0,
 	    0,
 	    NULL
 
@@ -225,9 +230,9 @@
 #define IMMEDIATE_WRITE 1
 
 static signed int do_hwc_write (int from_user, unsigned char *,
-					unsigned int,
-					unsigned char,
-					unsigned char);
+				unsigned int,
+				unsigned char,
+				unsigned char);
 
 static asmlinkage int 
 internal_print (char write_time, char *fmt,...)
@@ -236,10 +241,10 @@
 	int i;
 	unsigned char buf[512];
 
-	va_start(args, fmt);
-	i = vsprintf(buf, fmt, args);
-	va_end(args);
-	return do_hwc_write(0, buf, i, CODE_ASCII, write_time);
+	va_start (args, fmt);
+	i = vsprintf (buf, fmt, args);
+	va_end (args);
+	return do_hwc_write (0, buf, i, CODE_ASCII, write_time);
 }
 
 int 
@@ -250,18 +255,18 @@
 	unsigned char buf[512];
 	unsigned long flags;
 	int retval;
-	
-	spin_lock_irqsave(&hwc_data.lock, flags);
 
-        i = vsprintf(buf, fmt, args);
-	va_end(args);
-	retval = do_hwc_write(0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
-	
-	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
+	i = vsprintf (buf, fmt, args);
+	va_end (args);
+	retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
+
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
 	return retval;
 }
-	
+
 #ifdef DUMP_HWCB_INPUT
 
 static void 
@@ -275,46 +280,46 @@
 
 	old_final_nl = hwc_data.ioctls.final_nl;
 	hwc_data.ioctls.final_nl = 1;
-	
-	internal_print(DELAYED_WRITE, "\n%8x   ", area);
+
+	internal_print (DELAYED_WRITE, "\n%8x   ", area);
 
 	for (index = 0; index < count; index++) {
-		
+
 		if (area[index] <= 0xF)
-			internal_print(DELAYED_WRITE, "0%x", area[index]);
+			internal_print (DELAYED_WRITE, "0%x", area[index]);
 		else
 			internal_print (DELAYED_WRITE, "%x", area[index]);
-		
+
 		if ((index & 0xF) == 0xF)
-			internal_print(DELAYED_WRITE, "\n%8x   ",
-						 &area[index + 1]);
-		else	if ((index & 3) == 3)
-				internal_print(DELAYED_WRITE, " ");
+			internal_print (DELAYED_WRITE, "\n%8x   ",
+					&area[index + 1]);
+		else if ((index & 3) == 3)
+			internal_print (DELAYED_WRITE, " ");
 	}
-	
-	internal_print(IMMEDIATE_WRITE, "\n"); 
+
+	internal_print (IMMEDIATE_WRITE, "\n");
 
 	hwc_data.ioctls.final_nl = old_final_nl;
 }
-#endif	
+#endif
 
 static inline u32 
 service_call (
-	u32 hwc_command_word,
-	unsigned char hwcb[])
+		     u32 hwc_command_word,
+		     unsigned char hwcb[])
 {
 	unsigned int condition_code = 1;
 
-	__asm__ __volatile__("L 1, 0(0,%0) \n\t"
-			     "LRA 2, 0(0,%1) \n\t"
-			     ".long 0xB2200012 \n\t"
-			     :
-			     :"a"(&hwc_command_word), "a"(hwcb)
-			     :"1", "2", "memory");
-
-	__asm__ __volatile__("IPM %0 \n\t"
-			     "SRL %0, 28 \n\t"
-			     :"=r"(condition_code));
+	__asm__ __volatile__ ("L 1, 0(0,%0) \n\t"
+			      "LRA 2, 0(0,%1) \n\t"
+			      ".long 0xB2200012 \n\t"
+			      :
+			      :"a" (&hwc_command_word), "a" (hwcb)
+			      :"1", "2", "memory");
+
+	__asm__ __volatile__ ("IPM %0 \n\t"
+			      "SRL %0, 28 \n\t"
+			      :"=r" (condition_code));
 
 	return condition_code;
 }
@@ -324,8 +329,8 @@
 {
 	u32 param;
 
-	__asm__ __volatile__("L %0,128(0,0)\n\t"
-			     :"=r"(param));
+	__asm__ __volatile__ ("L %0,128(0,0)\n\t"
+			      :"=r" (param));
 
 	return ((unsigned char *) param);
 }
@@ -337,14 +342,14 @@
 
 	if (!BUF_HWCB)
 		return -ENOMEM;
-	
+
 	BUF_HWCB_MTO = 0;
 	BUF_HWCB_CHAR = 0;
 
 	hwcb = (write_hwcb_t *) BUF_HWCB;
 
-	memcpy(hwcb, &write_hwcb_template, sizeof(write_hwcb_t));
-	
+	memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
+
 	if (!hwc_data.write_nonprio && hwc_data.write_prio)
 		hwcb->msgbuf.type = ET_PMsgCmd;
 
@@ -363,27 +368,27 @@
 
 	if (!OUT_HWCB)
 		return -ENOMEM;
-	
-	if ((unsigned long)OUT_HWCB & 0xFFF) {
+
+	if ((unsigned long) OUT_HWCB & 0xFFF) {
 
 		bad_addr = OUT_HWCB;
 
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
-		__asm__("LHI 1,0xe30\n\t"
-			"LRA 2,0(0,%0) \n\t"
-			"J .+0 \n\t"
-			:
-			:"a"(bad_addr)
-			:"1", "2");
-#endif	
-		
+		__asm__ ("LHI 1,0xe30\n\t"
+			 "LRA 2,0(0,%0) \n\t"
+			 "J .+0 \n\t"
+	      :
+	      :	 "a" (bad_addr)
+	      :	 "1", "2");
+#endif
+
 		hwc_data.kmem_pages = 0;
-		if ((unsigned long)BUF_HWCB & 0xFFF) {
+		if ((unsigned long) BUF_HWCB & 0xFFF) {
 
 			lost_hwcb = hwc_data.hwcb_count;
 			lost_msg = ALL_HWCB_MTO;
 			lost_char = ALL_HWCB_CHAR;
-			
+
 			OUT_HWCB = NULL;
 			BUF_HWCB = NULL;
 			ALL_HWCB_MTO = 0;
@@ -399,27 +404,27 @@
 			ALL_HWCB_CHAR = BUF_HWCB_CHAR;
 			hwc_data.hwcb_count = 1;
 			page = (unsigned long) BUF_HWCB;
-			
+
 			if (page >= hwc_data.kmem_start &&
-			    page < hwc_data.kmem_end) {
-				
+			    page <= hwc_data.kmem_end) {
+
 				page_nr = (int)
-					  ((page - hwc_data.kmem_start) >> 12);
-				set_bit(page_nr, &hwc_data.kmem_pages);
+				    ((page - hwc_data.kmem_start) >> 12);
+				set_bit (page_nr, &hwc_data.kmem_pages);
 			}
 		}
-		
-		internal_print(
-			DELAYED_WRITE,
-			HWC_RW_PRINT_HEADER
+
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
 			"found invalid HWCB at address 0x%x. List corrupted. "
-			"Lost %i HWCBs with %i characters within up to %i "
-			"messages. Saved %i HWCB with last %i characters i"
-			"within up to %i messages.\n",
-			(unsigned int)bad_addr,
-			lost_hwcb, lost_char, lost_msg,
-			hwc_data.hwcb_count,
-			ALL_HWCB_CHAR, ALL_HWCB_MTO);
+			   "Lost %i HWCBs with %i characters within up to %i "
+			   "messages. Saved %i HWCB with last %i characters i"
+				       "within up to %i messages.\n",
+				       (unsigned int) bad_addr,
+				       lost_hwcb, lost_char, lost_msg,
+				       hwc_data.hwcb_count,
+				       ALL_HWCB_CHAR, ALL_HWCB_MTO);
 	}
 	return 0;
 }
@@ -430,18 +435,18 @@
 	int retval;
 
 	if (hwc_data.hwcb_count < 2)
-#ifdef DUMP_HWC_WRITE_LIST_ERROR 
-		__asm__("LHI 1,0xe31\n\t"
-			"LRA 2,0(0,%0)\n\t"
-			"LRA 3,0(0,%1)\n\t"
-			"J .+0 \n\t"
-			:
-			:"a"(BUF_HWCB), "a"(OUT_HWCB)
-			:"1", "2", "3");
+#ifdef DUMP_HWC_WRITE_LIST_ERROR
+		__asm__ ("LHI 1,0xe31\n\t"
+			 "LRA 2,0(0,%0)\n\t"
+			 "LRA 3,0(0,%1)\n\t"
+			 "J .+0 \n\t"
+	      :
+	      :	 "a" (BUF_HWCB), "a" (OUT_HWCB)
+	      :	 "1", "2", "3");
 #else
 		return -EPERM;
-#endif	
-	
+#endif
+
 	if (hwc_data.current_hwcb == OUT_HWCB) {
 
 		if (hwc_data.hwcb_count > 2) {
@@ -471,34 +476,34 @@
 	ALL_HWCB_MTO -= BUF_HWCB_MTO;
 	ALL_HWCB_CHAR -= BUF_HWCB_CHAR;
 
-	retval = prepare_write_hwcb();
+	retval = prepare_write_hwcb ();
 
 	if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
-		internal_print(
-			DELAYED_WRITE,
-			HWC_RW_PRINT_HEADER
-			"reached my own limit of "
-			"allowed buffer space for output (%i HWCBs = %li "
-			"bytes), skipped content of oldest HWCB %i time(s) "
-			"(%i lines = %i characters)\n",
-			hwc_data.ioctls.max_hwcb,
-			hwc_data.ioctls.max_hwcb * PAGE_SIZE,
-			BUF_HWCB_TIMES_LOST,
-			BUF_HWCB_MTO_LOST,
-			BUF_HWCB_CHAR_LOST);
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "reached my own limit of "
+			    "allowed buffer space for output (%i HWCBs = %li "
+			  "bytes), skipped content of oldest HWCB %i time(s) "
+				       "(%i lines = %i characters)\n",
+				       hwc_data.ioctls.max_hwcb,
+				       hwc_data.ioctls.max_hwcb * PAGE_SIZE,
+				       BUF_HWCB_TIMES_LOST,
+				       BUF_HWCB_MTO_LOST,
+				       BUF_HWCB_CHAR_LOST);
 	else
 		internal_print (
-			DELAYED_WRITE,
-			HWC_RW_PRINT_HEADER
-			"page allocation failed, "
-			"could not expand buffer for output (currently in "
-			"use: %i HWCBs = %li bytes), skipped content of "
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "page allocation failed, "
+			   "could not expand buffer for output (currently in "
+			     "use: %i HWCBs = %li bytes), skipped content of "
 			"oldest HWCB %i time(s) (%i lines = %i characters)\n",
-			hwc_data.hwcb_count,
-			hwc_data.hwcb_count * PAGE_SIZE,
-			BUF_HWCB_TIMES_LOST,
-			BUF_HWCB_MTO_LOST,
-			BUF_HWCB_CHAR_LOST);
+				       hwc_data.hwcb_count,
+				       hwc_data.hwcb_count * PAGE_SIZE,
+				       BUF_HWCB_TIMES_LOST,
+				       BUF_HWCB_MTO_LOST,
+				       BUF_HWCB_CHAR_LOST);
 
 	return retval;
 }
@@ -508,16 +513,16 @@
 {
 	unsigned char *page;
 	int page_nr;
-	
+
 	if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
 		return -ENOMEM;
-	
-	page_nr = find_first_zero_bit(&hwc_data.kmem_pages, MAX_KMEM_PAGES);
+
+	page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES);
 	if (page_nr < hwc_data.ioctls.kmem_hwcb) {
 
 		page = (unsigned char *)
-				(hwc_data.kmem_start + (page_nr << 12));
-		set_bit(page_nr, &hwc_data.kmem_pages);
+		    (hwc_data.kmem_start + (page_nr << 12));
+		set_bit (page_nr, &hwc_data.kmem_pages);
 	} else
 		page = (unsigned char *) __get_free_page (GFP_ATOMIC);
 
@@ -526,7 +531,7 @@
 
 	if (!OUT_HWCB)
 		OUT_HWCB = page;
-	else	
+	else
 		BUF_HWCB_NEXT = page;
 
 	BUF_HWCB = page;
@@ -535,7 +540,7 @@
 
 	hwc_data.hwcb_count++;
 
-	prepare_write_hwcb();
+	prepare_write_hwcb ();
 
 	BUF_HWCB_TIMES_LOST = 0;
 	BUF_HWCB_MTO_LOST = 0;
@@ -543,13 +548,13 @@
 
 #ifdef BUFFER_STRESS_TEST
 
-	internal_print(
-		DELAYED_WRITE,
-		"*** " HWC_RW_PRINT_HEADER
-		"page #%i at 0x%x for buffering allocated. ***\n",
-		hwc_data.hwcb_count, page);
+	internal_print (
+			       DELAYED_WRITE,
+			       "*** " HWC_RW_PRINT_HEADER
+			    "page #%i at 0x%x for buffering allocated. ***\n",
+			       hwc_data.hwcb_count, page);
 
-#endif	
+#endif
 
 	return 0;
 }
@@ -559,54 +564,53 @@
 {
 	unsigned long page;
 	int page_nr;
-        
-        if (!hwc_data.hwcb_count)
-                return -ENODATA;
-        
-        if (hwc_data.hwcb_count == 1) {
-
-                prepare_write_hwcb();
-                
-                ALL_HWCB_CHAR = 0;
-                ALL_HWCB_MTO = 0;
-                BUF_HWCB_TIMES_LOST = 0;
-                BUF_HWCB_MTO_LOST = 0;
-                BUF_HWCB_CHAR_LOST = 0;
+
+	if (!hwc_data.hwcb_count)
+		return -ENODATA;
+
+	if (hwc_data.hwcb_count == 1) {
+
+		prepare_write_hwcb ();
+
+		ALL_HWCB_CHAR = 0;
+		ALL_HWCB_MTO = 0;
+		BUF_HWCB_TIMES_LOST = 0;
+		BUF_HWCB_MTO_LOST = 0;
+		BUF_HWCB_CHAR_LOST = 0;
 	} else {
-                page = (unsigned long) OUT_HWCB;
-                
-                ALL_HWCB_MTO -= OUT_HWCB_MTO;
-                ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
-                hwc_data.hwcb_count--;
-                
-                OUT_HWCB = OUT_HWCB_NEXT;
-                
-                if (page >= hwc_data.kmem_start &&
-                    page < hwc_data.kmem_end) {
+		page = (unsigned long) OUT_HWCB;
+
+		ALL_HWCB_MTO -= OUT_HWCB_MTO;
+		ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
+		hwc_data.hwcb_count--;
+
+		OUT_HWCB = OUT_HWCB_NEXT;
 
-/*      memset((void *) page, 0, PAGE_SIZE); */
+		if (page >= hwc_data.kmem_start &&
+		    page <= hwc_data.kmem_end) {
+			/*memset((void *) page, 0, PAGE_SIZE); */
 
-                        page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
-                        clear_bit(page_nr, &hwc_data.kmem_pages);
+			page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
+			clear_bit (page_nr, &hwc_data.kmem_pages);
 		} else
-                	free_page(page);
+			free_page (page);
 #ifdef BUFFER_STRESS_TEST
 
-	        internal_print(
-			DELAYED_WRITE,
-			"*** " HWC_RW_PRINT_HEADER
-			"page at 0x%x released, %i pages still in use ***\n",
-			page, hwc_data.hwcb_count);
+		internal_print (
+				       DELAYED_WRITE,
+				       "*** " HWC_RW_PRINT_HEADER
+			 "page at 0x%x released, %i pages still in use ***\n",
+				       page, hwc_data.hwcb_count);
 
-#endif  
-        }
+#endif
+	}
 	return 0;
 }
 
 static int 
 add_mto (
-	unsigned char *message,
-	unsigned short int count)
+		unsigned char *message,
+		unsigned short int count)
 {
 	unsigned short int mto_size;
 	write_hwcb_t *hwcb;
@@ -619,32 +623,38 @@
 	if (BUF_HWCB == hwc_data.current_hwcb)
 		return -ENOMEM;
 
-	mto_size = sizeof(mto_t) + count;
+	mto_size = sizeof (mto_t) + count;
 
 	hwcb = (write_hwcb_t *) BUF_HWCB;
-	
+
 	if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)
 		return -ENOMEM;
 
 	mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);
 
-	memcpy(mto, &mto_template, sizeof(mto_t));
+	memcpy (mto, &mto_template, sizeof (mto_t));
 
-	dest = (void *) (((unsigned long) mto) + sizeof(mto_t));
+	dest = (void *) (((unsigned long) mto) + sizeof (mto_t));
 
-	memcpy(dest, message, count);
+	memcpy (dest, message, count);
 
 	mto->length += count;
-	
-	hwcb->length		+= mto_size;
-	hwcb->msgbuf.length	+= mto_size;
-	hwcb->msgbuf.mdb.length	+= mto_size;
+
+	hwcb->length += mto_size;
+	hwcb->msgbuf.length += mto_size;
+	hwcb->msgbuf.mdb.length += mto_size;
 
 	BUF_HWCB_MTO++;
 	ALL_HWCB_MTO++;
 	BUF_HWCB_CHAR += count;
 	ALL_HWCB_CHAR += count;
 
+#ifdef MEASURE_HWC_OUTPUT
+
+	hwc_data.ioctls.measured_lines++;
+	hwc_data.ioctls.measured_chars += count;
+#endif
+
 	return count;
 }
 
@@ -659,38 +669,41 @@
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
-	
-	retval = sane_write_hwcb();
+
+	retval = sane_write_hwcb ();
 	if (retval < 0)
 		return retval;
 
 	if (!OUT_HWCB_MTO)
 		return -ENODATA;
 
-	condition_code = service_call(HWC_CMDW_WRITEDATA, OUT_HWCB);
+	condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
 
-#ifdef DUMP_HWC_WRITE_ERROR 
+#ifdef DUMP_HWC_WRITE_ERROR
 	if (condition_code != HWC_COMMAND_INITIATED)
-		__asm__("LHI 1,0xe20\n\t"
-			"L 2,0(0,%0)\n\t"
-			"LRA 3,0(0,%1)\n\t"
-			"J .+0 \n\t"
-			:
-			:"a"(&condition_code), "a"(OUT_HWCB)
-			:"1", "2", "3");
-#endif	
+		__asm__ ("LHI 1,0xe20\n\t"
+			 "L 2,0(0,%0)\n\t"
+			 "LRA 3,0(0,%1)\n\t"
+			 "J .+0 \n\t"
+	      :
+	      :	 "a" (&condition_code), "a" (OUT_HWCB)
+	      :	 "1", "2", "3");
+#endif
 
 	switch (condition_code) {
-		case HWC_COMMAND_INITIATED :
-			hwc_data.current_servc = HWC_CMDW_WRITEDATA;
-			hwc_data.current_hwcb = OUT_HWCB;
-			retval = condition_code;
-			break;
-		case HWC_BUSY :
-			retval = -EBUSY;
-			break;
-		default :
-			retval = -EIO;
+	case HWC_COMMAND_INITIATED:
+		hwc_data.current_servc = HWC_CMDW_WRITEDATA;
+		hwc_data.current_hwcb = OUT_HWCB;
+		retval = condition_code;
+#ifdef MEASURE_HWC_OUTPUT
+		hwc_data.ioctls.measured_wcalls++;
+#endif
+		break;
+	case HWC_BUSY:
+		retval = -EBUSY;
+		break;
+	default:
+		retval = -EIO;
 	}
 
 	return retval;
@@ -700,9 +713,9 @@
 flush_hwcbs (void)
 {
 	while (hwc_data.hwcb_count > 1)
-		release_write_hwcb();
+		release_write_hwcb ();
 
-	release_write_hwcb();
+	release_write_hwcb ();
 
 	hwc_data.flags &= ~HWC_FLUSH;
 }
@@ -716,7 +729,7 @@
 #ifdef DUMP_HWC_WRITE_ERROR
 	unsigned char *param;
 
-	param = ext_int_param();
+	param = ext_int_param ();
 	if (param != hwc_data.current_hwcb) {
 		internal_print (
 				       DELAYED_WRITE,
@@ -734,42 +747,42 @@
 
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 	if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
-		__asm__("LHI 1,0xe22\n\t"
-			"LRA 2,0(0,%0)\n\t"
-			"LRA 3,0(0,%1)\n\t"
-			"LRA 4,0(0,%2)\n\t"
-			"LRA 5,0(0,%3)\n\t"
-			"J .+0 \n\t"
-			:
-			:"a"(OUT_HWCB),
-			 "a"(hwc_data.current_hwcb),
-			 "a"(BUF_HWCB),
+		__asm__ ("LHI 1,0xe22\n\t"
+			 "LRA 2,0(0,%0)\n\t"
+			 "LRA 3,0(0,%1)\n\t"
+			 "LRA 4,0(0,%2)\n\t"
+			 "LRA 5,0(0,%3)\n\t"
+			 "J .+0 \n\t"
+	      :
+	      :	 "a" (OUT_HWCB),
+			 "a" (hwc_data.current_hwcb),
+			 "a" (BUF_HWCB),
 			 "a" (hwcb)
-			:"1", "2", "3", "4", "5");
+	      :	 "1", "2", "3", "4", "5");
 	}
 #endif
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	if (hwcb->response_code != 0x0020) {
-		__asm__("LHI 1,0xe21\n\t"
-			"LRA 2,0(0,%0)\n\t"
-			"LRA 3,0(0,%1)\n\t"
-			"LRA 4,0(0,%2)\n\t"
-			"LH 5,0(0,%3)\n\t"
-			"SRL 5,8(0)\n\t"
-			"J .+0 \n\t"
-			:
-			:"a"(OUT_HWCB), "a"(hwc_data.current_hwcb),
-			 "a"(BUF_HWCB),
-			 "a"(&(hwc_data.hwcb_count))
-			:"1", "2", "3", "4", "5");
+		__asm__ ("LHI 1,0xe21\n\t"
+			 "LRA 2,0(0,%0)\n\t"
+			 "LRA 3,0(0,%1)\n\t"
+			 "LRA 4,0(0,%2)\n\t"
+			 "LH 5,0(0,%3)\n\t"
+			 "SRL 5,8(0)\n\t"
+			 "J .+0 \n\t"
+	      :
+	      :	 "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
+			 "a" (BUF_HWCB),
+			 "a" (&(hwc_data.hwcb_count))
+	      :	 "1", "2", "3", "4", "5");
 	}
-#endif	
+#endif
 
 	if (hwcb->response_code == 0x0020) {
 
 		retval = OUT_HWCB_CHAR;
-		release_write_hwcb();
+		release_write_hwcb ();
 	} else {
 		internal_print (
 				       DELAYED_WRITE,
@@ -787,53 +800,53 @@
 	hwc_data.current_hwcb = NULL;
 
 	if (hwc_data.flags & HWC_FLUSH)
-		flush_hwcbs();
+		flush_hwcbs ();
 
 	return retval;
 }
 
 static void 
 do_put_line (
-	unsigned char * message,
-	unsigned short count)
+		    unsigned char *message,
+		    unsigned short count)
 {
 
-	if (add_mto(message, count) != count) {
+	if (add_mto (message, count) != count) {
+
+		if (allocate_write_hwcb () < 0)
+			reuse_write_hwcb ();
 
-		if (allocate_write_hwcb() < 0)
-			reuse_write_hwcb();
-		
-#ifdef DUMP_HWC_WRITE_LIST_ERROR 
-		if (add_mto(message, count) != count)
-			__asm__("LHI 1,0xe32\n\t"
-				"LRA 2,0(0,%0)\n\t"
-				"L 3,0(0,%1)\n\t"
-				"LRA 4,0(0,%2)\n\t"
-				"LRA 5,0(0,%3)\n\t"
-				"J .+0 \n\t"
-				:
-				:"a"(message), "a"(&hwc_data.kmem_pages),
-				 "a"(BUF_HWCB), "a"(OUT_HWCB)
-				:"1", "2", "3", "4", "5");
+#ifdef DUMP_HWC_WRITE_LIST_ERROR
+		if (add_mto (message, count) != count)
+			__asm__ ("LHI 1,0xe32\n\t"
+				 "LRA 2,0(0,%0)\n\t"
+				 "L 3,0(0,%1)\n\t"
+				 "LRA 4,0(0,%2)\n\t"
+				 "LRA 5,0(0,%3)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (message), "a" (&hwc_data.kmem_pages),
+				 "a" (BUF_HWCB), "a" (OUT_HWCB)
+		      :	 "1", "2", "3", "4", "5");
 #else
-		add_mto(message, count);
-#endif	
+		add_mto (message, count);
+#endif
 	}
 }
 
 static void 
 put_line (
-	unsigned char * message,
-	unsigned short count)
+		 unsigned char *message,
+		 unsigned short count)
 {
-	
+
 	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
-		del_timer(&hwc_data.write_timer);
+		del_timer (&hwc_data.write_timer);
 		hwc_data.flags &= ~HWC_TIMER_RUNS;
 	}
 	hwc_data.obuf_start += count;
 
-	do_put_line(message, count);
+	do_put_line (message, count);
 
 	hwc_data.obuf_start -= count;
 }
@@ -844,39 +857,39 @@
 	write_hwcb_t *hwcb;
 
 	if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb))
-		allocate_write_hwcb();
+		allocate_write_hwcb ();
 
 	hwcb = (write_hwcb_t *) BUF_HWCB;
 	hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm;
-} 
+}
 
 static void 
 hwc_write_timeout (unsigned long data)
 {
 	unsigned long flags;
-	
-	spin_lock_irqsave(&hwc_data.lock, flags);
-	
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
 	hwc_data.obuf_start = hwc_data.obuf_count;
 	if (hwc_data.obuf_count)
-		put_line(hwc_data.obuf, hwc_data.obuf_count);
+		put_line (hwc_data.obuf, hwc_data.obuf_count);
 	hwc_data.obuf_start = 0;
 
 	hwc_data.obuf_cursor = 0;
 	hwc_data.obuf_count = 0;
-	
-	write_event_data_1(); 
 
-	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	write_event_data_1 ();
+
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
 }
 
 static int 
 do_hwc_write (
-	int from_user,
+		     int from_user,
 		     unsigned char *msg,
-	unsigned int count,
-	unsigned char code,
-	unsigned char write_time)
+		     unsigned int count,
+		     unsigned char code,
+		     unsigned char write_time)
 {
 	unsigned int i_msg = 0;
 	unsigned short int spaces = 0;
@@ -889,18 +902,18 @@
 	if (hwc_data.obuf_start) {
 		obuf_cursor = 0;
 		obuf_count = 0;
-		obuf_columns = MIN(hwc_data.ioctls.columns,
-				   MAX_MESSAGE_SIZE - hwc_data.obuf_start);
+		obuf_columns = MIN (hwc_data.ioctls.columns,
+				    MAX_MESSAGE_SIZE - hwc_data.obuf_start);
 	} else {
 		obuf_cursor = hwc_data.obuf_cursor;
 		obuf_count = hwc_data.obuf_count;
 		obuf_columns = hwc_data.ioctls.columns;
 	}
-	
+
 	for (i_msg = 0; i_msg < count; i_msg++) {
 
 		if (from_user)
-			get_user(orig_ch, msg + i_msg);
+			get_user (orig_ch, msg + i_msg);
 		else
 			orig_ch = msg[i_msg];
 		if (code == CODE_EBCDIC)
@@ -909,42 +922,42 @@
 			ch = orig_ch;
 
 		processed_characters++;
-		
+
 		if ((obuf_cursor == obuf_columns) &&
 
 		    (ch != '\n') &&
 
 		    (ch != '\t')) {
-			put_line(&hwc_data.obuf[hwc_data.obuf_start],
-				 obuf_columns);
+			put_line (&hwc_data.obuf[hwc_data.obuf_start],
+				  obuf_columns);
 			obuf_cursor = 0;
 			obuf_count = 0;
 		}
 		switch (ch) {
 
-		   case '\n' :  
+		case '\n':
 
-			put_line(&hwc_data.obuf[hwc_data.obuf_start],
-				 obuf_count);
+			put_line (&hwc_data.obuf[hwc_data.obuf_start],
+				  obuf_count);
 			obuf_cursor = 0;
 			obuf_count = 0;
 			break;
 
-		   case '\a' :  
+		case '\a':
 
 			hwc_data.obuf_start += obuf_count;
-			set_alarm();
+			set_alarm ();
 			hwc_data.obuf_start -= obuf_count;
 
 			break;
 
-		   case '\t' :  
+		case '\t':
 
 			do {
 				if (obuf_cursor < obuf_columns) {
 					hwc_data.obuf[hwc_data.obuf_start +
-								obuf_cursor]
-						= 0x20;  
+						      obuf_cursor]
+					    = 0x20;
 					obuf_cursor++;
 				} else
 					break;
@@ -952,47 +965,47 @@
 
 			break;
 
-		   case '\f' :  
-		   case '\v' :  
+		case '\f':
+		case '\v':
 
 			spaces = obuf_cursor;
-			put_line(&hwc_data.obuf[hwc_data.obuf_start],
-				 obuf_count);
+			put_line (&hwc_data.obuf[hwc_data.obuf_start],
+				  obuf_count);
 			obuf_count = obuf_cursor;
 			while (spaces) {
 				hwc_data.obuf[hwc_data.obuf_start +
-						obuf_cursor - spaces]
-					= 0x20;  
+					      obuf_cursor - spaces]
+				    = 0x20;
 				spaces--;
 			}
 
 			break;
 
-		   case '\b' :  
+		case '\b':
 
 			if (obuf_cursor)
 				obuf_cursor--;
 			break;
 
-		   case '\r' :  
+		case '\r':
 
 			obuf_cursor = 0;
 			break;
 
-		   case 0x00 :  
+		case 0x00:
 
-			put_line(&hwc_data.obuf[hwc_data.obuf_start],
-				 obuf_count);
+			put_line (&hwc_data.obuf[hwc_data.obuf_start],
+				  obuf_count);
 			obuf_cursor = 0;
 			obuf_count = 0;
 			goto out;
 
-		   default:  
+		default:
 
-			if (isprint(ch))
+			if (isprint (ch))
 				hwc_data.obuf[hwc_data.obuf_start +
-						obuf_cursor++]
-					 = (code == CODE_ASCII) ?
+					      obuf_cursor++]
+				    = (code == CODE_ASCII) ?
 				    (MACHINE_IS_VM ?
 				     _ascebc[orig_ch] :
 				     _ascebc_500[orig_ch]) :
@@ -1006,9 +1019,9 @@
 
 		if (hwc_data.obuf_start ||
 		    (hwc_data.ioctls.final_nl == 0)) {
-			
-			put_line(&hwc_data.obuf[hwc_data.obuf_start],
-				 obuf_count);
+
+			put_line (&hwc_data.obuf[hwc_data.obuf_start],
+				  obuf_count);
 			obuf_cursor = 0;
 			obuf_count = 0;
 		} else {
@@ -1018,34 +1031,34 @@
 				if (hwc_data.flags & HWC_TIMER_RUNS) {
 
 					hwc_data.write_timer.expires =
-						jiffies +
-						hwc_data.ioctls.final_nl*HZ/10;
+					    jiffies +
+					    hwc_data.ioctls.final_nl * HZ / 10;
 				} else {
 
-					init_timer(&hwc_data.write_timer);
+					init_timer (&hwc_data.write_timer);
 					hwc_data.write_timer.function =
-						hwc_write_timeout;
+					    hwc_write_timeout;
 					hwc_data.write_timer.data =
-						(unsigned long)NULL;
+					    (unsigned long) NULL;
 					hwc_data.write_timer.expires =
-						jiffies +
-						hwc_data.ioctls.final_nl*HZ/10;
-					add_timer(&hwc_data.write_timer);
+					    jiffies +
+					    hwc_data.ioctls.final_nl * HZ / 10;
+					add_timer (&hwc_data.write_timer);
 					hwc_data.flags |= HWC_TIMER_RUNS;
 				}
 			} else;
 
-			}
+		}
 	} else;
 
-out :
+      out:
 
 	if (!hwc_data.obuf_start) {
 		hwc_data.obuf_cursor = obuf_cursor;
 		hwc_data.obuf_count = obuf_count;
 	}
 	if (write_time == IMMEDIATE_WRITE)
-		write_event_data_1();
+		write_event_data_1 ();
 
 	return processed_characters;
 }
@@ -1055,14 +1068,14 @@
 {
 	unsigned long flags;
 	int retval;
-	
-	spin_lock_irqsave(&hwc_data.lock, flags);
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
 
 	retval = do_hwc_write (from_user, (unsigned char *) msg,
 			       count, hwc_data.ioctls.code,
-							 IMMEDIATE_WRITE);
+			       IMMEDIATE_WRITE);
 
-	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
 	return retval;
 }
@@ -1073,15 +1086,15 @@
 	unsigned short int number = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&hwc_data.lock, flags);
+	spin_lock_irqsave (&hwc_data.lock, flags);
 
 	if (flag & IN_HWCB)
 		number += ALL_HWCB_CHAR;
-	
+
 	if (flag & IN_WRITE_BUF)
 		number += hwc_data.obuf_cursor;
-	
-	spin_unlock_irqrestore(&hwc_data.lock, flags);
+
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
 	return number;
 }
@@ -1092,7 +1105,7 @@
 	int i;
 	int nr = 0;
 
-	for (i = 0; i < (sizeof(arg) << 3); i++) {
+	for (i = 0; i < (sizeof (arg) << 3); i++) {
 		if (arg & 1)
 			nr++;
 		arg >>= 1;
@@ -1107,24 +1120,24 @@
 	unsigned int number = 0;
 	unsigned long flags;
 	write_hwcb_t *hwcb;
-	
-	spin_lock_irqsave(&hwc_data.lock, flags);
 
-        if (flag & IN_HWCB) {
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
+	if (flag & IN_HWCB) {
 
 		if (BUF_HWCB) {
 			hwcb = (write_hwcb_t *) BUF_HWCB;
-                	number += MAX_HWCB_ROOM - hwcb->length;
+			number += MAX_HWCB_ROOM - hwcb->length;
 		}
 		number += (hwc_data.ioctls.kmem_hwcb -
-			   nr_setbits(hwc_data.kmem_pages)) *
-			  (MAX_HWCB_ROOM -
-				(sizeof(write_hwcb_t) + sizeof(mto_t)));
+			   nr_setbits (hwc_data.kmem_pages)) *
+		    (MAX_HWCB_ROOM -
+		     (sizeof (write_hwcb_t) + sizeof (mto_t)));
 	}
-        if (flag & IN_WRITE_BUF)
-                number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
+	if (flag & IN_WRITE_BUF)
+		number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
 
-	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
 	return number;
 }
@@ -1134,19 +1147,19 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&hwc_data.lock, flags);
+	spin_lock_irqsave (&hwc_data.lock, flags);
 
 	if (flag & IN_HWCB) {
 		if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
-			flush_hwcbs();
+			flush_hwcbs ();
 		else
 			hwc_data.flags |= HWC_FLUSH;
 	}
 	if (flag & IN_WRITE_BUF) {
-		hwc_data.obuf_cursor = 0;	
+		hwc_data.obuf_cursor = 0;
 		hwc_data.obuf_count = 0;
 	}
-	spin_unlock_irqrestore(&hwc_data.lock, flags);
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
 }
 
 unsigned short int 
@@ -1170,7 +1183,7 @@
 
 				i_out++;
 
-				i_in++; 
+				i_in++;
 
 			} else
 				_case = ~_case;
@@ -1179,7 +1192,7 @@
 
 			if (_case) {
 
-				if (hwc_data.ioctls.tolower) 
+				if (hwc_data.ioctls.tolower)
 					buf[i_out] = _ebc_toupper[buf[i_in]];
 
 				else
@@ -1203,43 +1216,43 @@
 	int retval = 0;
 
 	switch (id) {
-		case GDS_ID_MDSMU :
-			name = "Multiple Domain Support Message Unit";
-			break;
-		case GDS_ID_MDSRouteInfo :
-			name = "MDS Routing Information";
-			break;
-		case GDS_ID_AgUnWrkCorr :
-			name = "Agent Unit of Work Correlator";
-			break;
-		case GDS_ID_SNACondReport :
-			name = "SNA Condition Report";
-			break;
-		case GDS_ID_CPMSU :
-			name = "CP Management Services Unit";
-			break;
-		case GDS_ID_RoutTargInstr :
-			name = "Routing and Targeting Instructions";
-			break;
-		case GDS_ID_OpReq :
-			name = "Operate Request";
-			break;
-		case GDS_ID_TextCmd :
-			name = "Text Command";
-			break;
+	case GDS_ID_MDSMU:
+		name = "Multiple Domain Support Message Unit";
+		break;
+	case GDS_ID_MDSRouteInfo:
+		name = "MDS Routing Information";
+		break;
+	case GDS_ID_AgUnWrkCorr:
+		name = "Agent Unit of Work Correlator";
+		break;
+	case GDS_ID_SNACondReport:
+		name = "SNA Condition Report";
+		break;
+	case GDS_ID_CPMSU:
+		name = "CP Management Services Unit";
+		break;
+	case GDS_ID_RoutTargInstr:
+		name = "Routing and Targeting Instructions";
+		break;
+	case GDS_ID_OpReq:
+		name = "Operate Request";
+		break;
+	case GDS_ID_TextCmd:
+		name = "Text Command";
+		break;
 
-		default :
-			name = "unknown GDS variable";
-			retval = -EINVAL;
+	default:
+		name = "unknown GDS variable";
+		retval = -EINVAL;
 	}
 
 	return retval;
 }
-#endif	
+#endif
 
 inline static gds_vector_t *
 find_gds_vector (
-	gds_vector_t *start, void *end, u16 id)
+			gds_vector_t * start, void *end, u16 id)
 {
 	gds_vector_t *vec;
 	gds_vector_t *retval = NULL;
@@ -1247,31 +1260,31 @@
 	vec = start;
 
 	while (((void *) vec) < end) {
-	 	if (vec->gds_id == id) {
+		if (vec->gds_id == id) {
 
 #ifdef DUMP_HWCB_INPUT
 			int retval_name;
 			unsigned char name[64];
 
-			retval_name = gds_vector_name(id, name);
-			internal_print(
-				DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"%s at 0x%x up to 0x%x, length: %d",
-				name,
-				(unsigned long) vec,
-				((unsigned long) vec) + vec->length - 1,
-				vec->length);
+			retval_name = gds_vector_name (id, name);
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					  "%s at 0x%x up to 0x%x, length: %d",
+					       name,
+					       (unsigned long) vec,
+				      ((unsigned long) vec) + vec->length - 1,
+					       vec->length);
 			if (retval_name < 0)
-				internal_print(
-					IMMEDIATE_WRITE,
-					", id: 0x%x\n",
-					vec->gds_id);
+				internal_print (
+						       IMMEDIATE_WRITE,
+						       ", id: 0x%x\n",
+						       vec->gds_id);
 			else
 				internal_print (
-					IMMEDIATE_WRITE,
-					"\n");
-#endif	
+						       IMMEDIATE_WRITE,
+						       "\n");
+#endif
 
 			retval = vec;
 			break;
@@ -1284,7 +1297,7 @@
 
 inline static gds_subvector_t *
 find_gds_subvector (
-	gds_subvector_t *start, void *end, u8 key)
+			   gds_subvector_t * start, void *end, u8 key)
 {
 	gds_subvector_t *subvec;
 	gds_subvector_t *retval = NULL;
@@ -1292,12 +1305,12 @@
 	subvec = start;
 
 	while (((void *) subvec) < end) {
-	 	if (subvec->key == key) {
+		if (subvec->key == key) {
 			retval = subvec;
 			break;
 		}
 		subvec = (gds_subvector_t *)
-				(((unsigned long) subvec) + subvec->length);
+		    (((unsigned long) subvec) + subvec->length);
 	}
 
 	return retval;
@@ -1311,17 +1324,17 @@
 	count = ((unsigned long) end) - ((unsigned long) start);
 
 	if (hwc_data.ioctls.tolower)
-		EBC_TOLOWER(start, count);
+		EBC_TOLOWER (start, count);
 
 	if (hwc_data.ioctls.delim)
-		count = seperate_cases(start, count);
+		count = seperate_cases (start, count);
 
 	if (hwc_data.ioctls.echo)
-		do_hwc_write(0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
+		do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
 
 	if (hwc_data.ioctls.code == CODE_ASCII) {
 		if (MACHINE_IS_VM)
-		EBCASC(start, count);
+			EBCASC (start, count);
 		else
 			EBCASC_500 (start, count);
 	}
@@ -1343,15 +1356,15 @@
 	subvec = start;
 
 	while (((void *) subvec) < end) {
-		subvec = find_gds_subvector(subvec, end, 0x30);
+		subvec = find_gds_subvector (subvec, end, 0x30);
 		if (!subvec)
 			break;
 		subvec_data = (void *)
-				(((unsigned long) subvec) + 
-						sizeof(gds_subvector_t));
+		    (((unsigned long) subvec) +
+		     sizeof (gds_subvector_t));
 		subvec_end = (void *)
-				(((unsigned long) subvec) + subvec->length);
-		retval += get_input(subvec_data, subvec_end);
+		    (((unsigned long) subvec) + subvec->length);
+		retval += get_input (subvec_data, subvec_end);
 		subvec = (gds_subvector_t *) subvec_end;
 	}
 
@@ -1369,16 +1382,16 @@
 	subvec = start;
 
 	while (((void *) subvec) < end) {
-		subvec = find_gds_subvector(
-					subvec, end, GDS_KEY_SelfDefTextMsg);
+		subvec = find_gds_subvector (
+					 subvec, end, GDS_KEY_SelfDefTextMsg);
 		if (!subvec)
 			break;
 		subvec_data = (gds_subvector_t *)
-				(((unsigned long) subvec) + 
-						sizeof(gds_subvector_t));
+		    (((unsigned long) subvec) +
+		     sizeof (gds_subvector_t));
 		subvec_end = (void *)
-				(((unsigned long) subvec) + subvec->length);
-		retval += eval_selfdeftextmsg(subvec_data, subvec_end);
+		    (((unsigned long) subvec) + subvec->length);
+		retval += eval_selfdeftextmsg (subvec_data, subvec_end);
 		subvec = (gds_subvector_t *) subvec_end;
 	}
 
@@ -1396,13 +1409,13 @@
 	vec = start;
 
 	while (((void *) vec) < end) {
-		vec = find_gds_vector(vec, end, GDS_ID_TextCmd);
+		vec = find_gds_vector (vec, end, GDS_ID_TextCmd);
 		if (!vec)
 			break;
 		vec_data = (gds_subvector_t *)
-				(((unsigned long) vec) + sizeof(gds_vector_t));
+		    (((unsigned long) vec) + sizeof (gds_vector_t));
 		vec_end = (void *) (((unsigned long) vec) + vec->length);
-		retval += eval_textcmd(vec_data, vec_end);
+		retval += eval_textcmd (vec_data, vec_end);
 		vec = (gds_vector_t *) vec_end;
 	}
 
@@ -1417,12 +1430,12 @@
 	void *vec_end;
 	int retval = 0;
 
-	vec = find_gds_vector(start, end, GDS_ID_CPMSU);
+	vec = find_gds_vector (start, end, GDS_ID_CPMSU);
 	if (vec) {
 		vec_data = (gds_vector_t *)
-				(((unsigned long) vec) + sizeof(gds_vector_t));
+		    (((unsigned long) vec) + sizeof (gds_vector_t));
 		vec_end = (void *) (((unsigned long) vec) + vec->length);
-		retval = eval_cpmsu(vec_data, vec_end);
+		retval = eval_cpmsu (vec_data, vec_end);
 	}
 	return retval;
 }
@@ -1435,12 +1448,12 @@
 	void *vec_end;
 	int retval = 0;
 
-	vec = find_gds_vector(start, end, GDS_ID_MDSMU);
+	vec = find_gds_vector (start, end, GDS_ID_MDSMU);
 	if (vec) {
 		vec_data = (gds_vector_t *)
-				(((unsigned long) vec) + sizeof(gds_vector_t));
+		    (((unsigned long) vec) + sizeof (gds_vector_t));
 		vec_end = (void *) (((unsigned long) vec) + vec->length);
-		retval = eval_mdsmu(vec_data, vec_end);
+		retval = eval_mdsmu (vec_data, vec_end);
 	}
 	return retval;
 }
@@ -1456,39 +1469,39 @@
 	evbuf = (evbuf_t *) start;
 	while (((void *) evbuf) < end) {
 		evbuf_data = (gds_vector_t *)
-				(((unsigned long) evbuf) + sizeof(evbuf_t));
+		    (((unsigned long) evbuf) + sizeof (evbuf_t));
 		evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length);
 		switch (evbuf->type) {
-			case ET_OpCmd :
-			case ET_CntlProgOpCmd :
-			case ET_PMsgCmd :
+		case ET_OpCmd:
+		case ET_CntlProgOpCmd:
+		case ET_PMsgCmd:
 #ifdef DUMP_HWCB_INPUT
-				
-				internal_print(
-					DELAYED_WRITE,
-					HWC_RW_PRINT_HEADER
-					"event buffer "
-					"at 0x%x up to 0x%x, length: %d\n",
-					(unsigned long) evbuf,
-					(unsigned long) (evbuf_end - 1),
-					evbuf->length);
-				dump_storage_area((void *)evbuf, evbuf->length);
+
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "event buffer "
+					   "at 0x%x up to 0x%x, length: %d\n",
+					       (unsigned long) evbuf,
+					       (unsigned long) (evbuf_end - 1),
+					       evbuf->length);
+			dump_storage_area ((void *) evbuf, evbuf->length);
 #endif
-				retval += eval_evbuf(evbuf_data, evbuf_end);
-				break;
-			case ET_StateChange :
-				
-				retval = -ENOSYS;
-				break;
-			default :
-				printk(
-					KERN_WARNING
-					HWC_RW_PRINT_HEADER
-					"unconditional read: "
-					"unknown event buffer found, "
-					"type 0x%x",
-					evbuf->type);
-				retval = -ENOSYS;
+			retval += eval_evbuf (evbuf_data, evbuf_end);
+			break;
+		case ET_StateChange:
+
+			retval = -ENOSYS;
+			break;
+		default:
+			printk (
+				       KERN_WARNING
+				       HWC_RW_PRINT_HEADER
+				       "unconditional read: "
+				       "unknown event buffer found, "
+				       "type 0x%x",
+				       evbuf->type);
+			retval = -ENOSYS;
 		}
 		evbuf = (evbuf_t *) evbuf_end;
 	}
@@ -1501,40 +1514,40 @@
 	unsigned short int condition_code;
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 	int retval;
-	
+
 	if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
 		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
-	
-	memset(hwcb, 0x00, PAGE_SIZE); 
-	memcpy(hwcb, &read_hwcb_template, sizeof(read_hwcb_t));
 
-	condition_code = service_call(HWC_CMDW_READDATA, hwc_data.page);
+	memset (hwcb, 0x00, PAGE_SIZE);
+	memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
 
-#ifdef DUMP_HWC_READ_ERROR 
+	condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page);
+
+#ifdef DUMP_HWC_READ_ERROR
 	if (condition_code == HWC_NOT_OPERATIONAL)
-		__asm__("LHI 1,0xe40\n\t"
-			"L 2,0(0,%0)\n\t"
-			"LRA 3,0(0,%1)\n\t"
-			"J .+0 \n\t"
-			:
-			:"a"(&condition_code), "a"(hwc_data.page)
-			:"1", "2", "3");
-#endif	
+		__asm__ ("LHI 1,0xe40\n\t"
+			 "L 2,0(0,%0)\n\t"
+			 "LRA 3,0(0,%1)\n\t"
+			 "J .+0 \n\t"
+	      :
+	      :	 "a" (&condition_code), "a" (hwc_data.page)
+	      :	 "1", "2", "3");
+#endif
 
 	switch (condition_code) {
-		case HWC_COMMAND_INITIATED :
-			hwc_data.current_servc = HWC_CMDW_READDATA;
-			hwc_data.current_hwcb = hwc_data.page;
-			retval = condition_code;
-			break;
-		case HWC_BUSY :
-			retval = -EBUSY;
-			break;
-		default :
-			retval = -EIO;
+	case HWC_COMMAND_INITIATED:
+		hwc_data.current_servc = HWC_CMDW_READDATA;
+		hwc_data.current_hwcb = hwc_data.page;
+		retval = condition_code;
+		break;
+	case HWC_BUSY:
+		retval = -EBUSY;
+		break;
+	default:
+		retval = -EIO;
 	}
 
 	return retval;
@@ -1545,33 +1558,33 @@
 {
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 
-#ifdef DUMP_HWC_READ_ERROR 
+#ifdef DUMP_HWC_READ_ERROR
 	if ((hwcb->response_code != 0x0020) &&
 	    (hwcb->response_code != 0x0220) &&
 	    (hwcb->response_code != 0x60F0) &&
 	    (hwcb->response_code != 0x62F0))
-		__asm__("LHI 1,0xe41\n\t"
-			"LRA 2,0(0,%0)\n\t"
-			"L 3,0(0,%1)\n\t"
-			"J .+0\n\t"
-			:
-			:"a"(hwc_data.page), "a"(&(hwcb->response_code))
-			:"1", "2", "3");
-#endif	
+		__asm__ ("LHI 1,0xe41\n\t"
+			 "LRA 2,0(0,%0)\n\t"
+			 "L 3,0(0,%1)\n\t"
+			 "J .+0\n\t"
+	      :
+	      :	 "a" (hwc_data.page), "a" (&(hwcb->response_code))
+	      :	 "1", "2", "3");
+#endif
 
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
 
 	switch (hwcb->response_code) {
 
-	   case 0x0020 :
-	   case 0x0220 : 
-		return process_evbufs(
-			(void *) (((unsigned long) hwcb) + sizeof(read_hwcb_t)),
-			(void *) (((unsigned long) hwcb) + hwcb->length));
+	case 0x0020:
+	case 0x0220:
+		return process_evbufs (
+		     (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)),
+			    (void *) (((unsigned long) hwcb) + hwcb->length));
 
-	   case 0x60F0 :
-	   case 0x62F0 : 
+	case 0x60F0:
+	case 0x62F0:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
@@ -1581,67 +1594,67 @@
 				       hwcb->response_code);
 		return 0;
 
-	   case 0x0100 :
-		internal_print(
-			IMMEDIATE_WRITE,
-			HWC_RW_PRINT_HEADER
-			"unconditional read: HWCB boundary violation - this "
-			"must not occur in a correct driver, please contact "
-			"author\n");
+	case 0x0100:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
+			 "unconditional read: HWCB boundary violation - this "
+			 "must not occur in a correct driver, please contact "
+				       "author\n");
 		return -EIO;
 
-	   case 0x0300 :
-		internal_print(
-			IMMEDIATE_WRITE,
-			HWC_RW_PRINT_HEADER
-			"unconditional read: "
+	case 0x0300:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "unconditional read: "
 			"insufficient HWCB length - this must not occur in a "
-			"correct driver, please contact author\n");
+				   "correct driver, please contact author\n");
 		return -EIO;
 
-	   case 0x01F0 :
-		internal_print(
-			IMMEDIATE_WRITE, 
-			HWC_RW_PRINT_HEADER
-			"unconditional read: "
-			"invalid command - this must not occur in a correct "
-			"driver, please contact author\n");
+	case 0x01F0:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "unconditional read: "
+			 "invalid command - this must not occur in a correct "
+				       "driver, please contact author\n");
 		return -EIO;
 
-	   case 0x40F0 :
-		internal_print(
-			IMMEDIATE_WRITE,
-			HWC_RW_PRINT_HEADER
-			"unconditional read: invalid function code - this "
-			"must not occur in a correct driver, please contact "
-			"author\n");
+	case 0x40F0:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
+			   "unconditional read: invalid function code - this "
+			 "must not occur in a correct driver, please contact "
+				       "author\n");
 		return -EIO;
 
-	   case 0x70F0 :
-		internal_print(
-			IMMEDIATE_WRITE,
-			HWC_RW_PRINT_HEADER
-			"unconditional read: invalid selection mask - this "
-			"must not occur in a correct driver, please contact "
-			"author\n");
+	case 0x70F0:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
+			  "unconditional read: invalid selection mask - this "
+			 "must not occur in a correct driver, please contact "
+				       "author\n");
 		return -EIO;
 
-	   case 0x0040 :
-		internal_print(
-			IMMEDIATE_WRITE,
-			HWC_RW_PRINT_HEADER
-			"unconditional read: HWC equipment check - don't "
-			"know how to handle this case\n");
+	case 0x0040:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
+			    "unconditional read: HWC equipment check - don't "
+				       "know how to handle this case\n");
 		return -EIO;
-	   
-	   default :
-		internal_print(
-			IMMEDIATE_WRITE,
-			HWC_RW_PRINT_HEADER
+
+	default:
+		internal_print (
+				       IMMEDIATE_WRITE,
+				       HWC_RW_PRINT_HEADER
 			"unconditional read: invalid response code %x - this "
-			"must not occur in a correct driver, please contact "
-			"author\n",
-			hwcb->response_code);
+			 "must not occur in a correct driver, please contact "
+				       "author\n",
+				       hwcb->response_code);
 		return -EIO;
 	}
 }
@@ -1651,32 +1664,32 @@
 {
 	unsigned int condition_code;
 	int retval;
-	
-	condition_code = service_call(HWC_CMDW_WRITEMASK, hwc_data.page);
+
+	condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page);
 
 #ifdef DUMP_HWC_INIT_ERROR
 
 	if (condition_code == HWC_NOT_OPERATIONAL)
-		__asm__("LHI 1,0xe10\n\t"
-			"L 2,0(0,%0)\n\t"
-			"LRA 3,0(0,%1)\n\t"
-			"J .+0\n\t"
-			:
-			:"a"(&condition_code), "a"(hwc_data.page)
-			:"1", "2", "3");
-#endif	
+		__asm__ ("LHI 1,0xe10\n\t"
+			 "L 2,0(0,%0)\n\t"
+			 "LRA 3,0(0,%1)\n\t"
+			 "J .+0\n\t"
+	      :
+	      :	 "a" (&condition_code), "a" (hwc_data.page)
+	      :	 "1", "2", "3");
+#endif
 
 	switch (condition_code) {
-		case HWC_COMMAND_INITIATED :
-			hwc_data.current_servc = HWC_CMDW_WRITEMASK;
-			hwc_data.current_hwcb = hwc_data.page;
-			retval = condition_code;
-			break;
-		case HWC_BUSY :
-			retval = -EBUSY;
-			break;
-		default :
-			retval = -EIO;
+	case HWC_COMMAND_INITIATED:
+		hwc_data.current_servc = HWC_CMDW_WRITEMASK;
+		hwc_data.current_hwcb = hwc_data.page;
+		retval = condition_code;
+		break;
+	case HWC_BUSY:
+		retval = -EBUSY;
+		break;
+	default:
+		retval = -EIO;
 	}
 
 	return retval;
@@ -1690,10 +1703,10 @@
 
 	if (hwcb->hwc_receive_mask & ET_Msg_Mask)
 		hwc_data.write_nonprio = 1;
-	
+
 	if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
 		hwc_data.write_prio = 1;
-	
+
 	if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
 		internal_print (DELAYED_WRITE,
 				HWC_RW_PRINT_HEADER
@@ -1710,16 +1723,16 @@
 	    (!hwc_data.write_nonprio) ||
 	    ((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
 #ifdef DUMP_HWC_INIT_ERROR
-		__asm__("LHI 1,0xe11\n\t"
-			"LRA 2,0(0,%0)\n\t"
-			"L 3,0(0,%1)\n\t"
-			"J .+0\n\t"
-			:
-			:"a"(hwcb), "a"(&(hwcb->response_code))
-			:"1", "2", "3");
+		__asm__ ("LHI 1,0xe11\n\t"
+			 "LRA 2,0(0,%0)\n\t"
+			 "L 3,0(0,%1)\n\t"
+			 "J .+0\n\t"
+	      :
+	      :	 "a" (hwcb), "a" (&(hwcb->response_code))
+	      :	 "1", "2", "3");
 #else
 		retval = -EIO;
-#endif	
+#endif
 
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
@@ -1732,7 +1745,7 @@
 {
 	int retval = 0;
 	hwc_ioctls_t tmp;
-	
+
 	if (ioctls->width_htab > MAX_MESSAGE_SIZE) {
 		if (correct)
 			tmp.width_htab = MAX_MESSAGE_SIZE;
@@ -1742,7 +1755,7 @@
 		tmp.width_htab = ioctls->width_htab;
 
 	tmp.echo = ioctls->echo;
-	
+
 	if (ioctls->columns > MAX_MESSAGE_SIZE) {
 		if (correct)
 			tmp.columns = MAX_MESSAGE_SIZE;
@@ -1750,21 +1763,21 @@
 			retval = -EINVAL;
 	} else
 		tmp.columns = ioctls->columns;
-	
+
 	switch (ioctls->code) {
-		case CODE_EBCDIC :
-		case CODE_ASCII :
-			tmp.code = ioctls->code;
-			break;
-		default :
-			if (correct)
-				tmp.code = CODE_ASCII;
+	case CODE_EBCDIC:
+	case CODE_ASCII:
+		tmp.code = ioctls->code;
+		break;
+	default:
+		if (correct)
+			tmp.code = CODE_ASCII;
 		else
 			retval = -EINVAL;
 	}
-				
+
 	tmp.final_nl = ioctls->final_nl;
-	
+
 	if (ioctls->max_hwcb < 2) {
 		if (correct)
 			tmp.max_hwcb = 2;
@@ -1772,9 +1785,9 @@
 			retval = -EINVAL;
 	} else
 		tmp.max_hwcb = ioctls->max_hwcb;
-	
+
 	tmp.tolower = ioctls->tolower;
-	
+
 	if (ioctls->kmem_hwcb > ioctls->max_hwcb) {
 		if (correct)
 			tmp.kmem_hwcb = ioctls->max_hwcb;
@@ -1782,7 +1795,7 @@
 			retval = -EINVAL;
 	} else
 		tmp.kmem_hwcb = ioctls->kmem_hwcb;
-	
+
 	if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) {
 		if (correct)
 			ioctls->kmem_hwcb = MAX_KMEM_PAGES;
@@ -1797,6 +1810,10 @@
 	}
 	tmp.delim = ioctls->delim;
 
+	tmp.measured_lines = ioctls->measured_lines;
+	tmp.measured_chars = ioctls->measured_chars;
+	tmp.measured_wcalls = ioctls->measured_wcalls;
+
 	if (!(retval < 0))
 		hwc_data.ioctls = tmp;
 
@@ -1864,7 +1881,7 @@
 	if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
 		panic ("Couldn't request external interrupts 0x2401");
 
-	spin_lock_init(&hwc_data.lock);
+	spin_lock_init (&hwc_data.lock);
 
 #ifdef USE_VM_DETECTION
 
@@ -1880,7 +1897,7 @@
 		hwc_data.init_ioctls.delim = 0;
 	}
 #endif
-	retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1);
+	retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
 
 	*kmem_start = (*kmem_start + PAGE_SIZE - 1) & -4096L;
 	hwc_data.kmem_start = *kmem_start;
@@ -1889,26 +1906,26 @@
 
 	retval = do_hwc_init ();
 
-        ctl_set_bit(0, 9);
+	ctl_set_bit (0, 9);
 
-#ifdef BUFFER_STRESS_TEST 
+#ifdef BUFFER_STRESS_TEST
 
-	internal_print(
-		DELAYED_WRITE,
-		HWC_RW_PRINT_HEADER 
-		"use %i bytes for buffering.\n", 
-		hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
+	internal_print (
+			       DELAYED_WRITE,
+			       HWC_RW_PRINT_HEADER
+			       "use %i bytes for buffering.\n",
+			       hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
 	for (i = 0; i < 500; i++) {
 		hwcb = (init_hwcb_t *) BUF_HWCB;
-		internal_print(
-			DELAYED_WRITE, 
-			HWC_RW_PRINT_HEADER
-			"This is stress test message #%i, free: %i bytes\n", 
-			i, 
-			MAX_HWCB_ROOM - (hwcb->length + sizeof(mto_t)));
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+			  "This is stress test message #%i, free: %i bytes\n",
+				       i,
+			     MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t)));
 	}
 
-#endif	
+#endif
 
 	return /*retval */ 0;
 }
@@ -1956,34 +1973,34 @@
 					" temporary breakdown\n");
 		}
 	} else {
-	spin_lock(&hwc_data.lock);
+		spin_lock (&hwc_data.lock);
 
-	if (!hwc_data.current_servc) {
+		if (!hwc_data.current_servc) {
 
-		unconditional_read_1();
+			unconditional_read_1 ();
 
-	} else {
+		} else {
 
-		switch (hwc_data.current_servc) {
+			switch (hwc_data.current_servc) {
 
-			case HWC_CMDW_WRITEMASK :
+			case HWC_CMDW_WRITEMASK:
 
-				write_event_mask_2();
+				write_event_mask_2 ();
 				break;
-			
-			case HWC_CMDW_WRITEDATA :
 
-				write_event_data_2();
+			case HWC_CMDW_WRITEDATA:
+
+				write_event_data_2 ();
 				break;
 
-			case HWC_CMDW_READDATA :
+			case HWC_CMDW_READDATA:
 
-				unconditional_read_2();
+				unconditional_read_2 ();
 				break;
-		}		
+			}
 
-		write_event_data_1();
-	}
+			write_event_data_1 ();
+		}
 		if (hwc_data.calls != NULL)
 			if (hwc_data.calls->wake_up != NULL)
 				(hwc_data.calls->wake_up) ();
@@ -1996,7 +2013,7 @@
 {
 
 	spin_lock (&hwc_data.lock);
-	spin_unlock(&hwc_data.lock);
+	spin_unlock (&hwc_data.lock);
 
 	asm volatile ("STCTL 0,0,%0":"=m" (cr0));
 	cr0_save = cr0;
@@ -2021,39 +2038,45 @@
 	int retval = 0;
 	unsigned long flags;
 	unsigned int obuf;
-	
-	spin_lock_irqsave(&hwc_data.lock, flags);
-	
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
 	switch (cmd) {
 
-	   case TIOCHWCSHTAB :
-		if (get_user(tmp.width_htab, (ioctl_htab_t *) arg))
+	case TIOCHWCSMEAS:
+		hwc_data.ioctls.measured_lines = 0;
+		hwc_data.ioctls.measured_chars = 0;
+		hwc_data.ioctls.measured_wcalls = 0;
+		break;
+
+	case TIOCHWCSHTAB:
+		if (get_user (tmp.width_htab, (ioctl_htab_t *) arg))
 			goto fault;
 		break;
-	   
-	   case TIOCHWCSECHO :
-                if (get_user(tmp.echo, (ioctl_echo_t *) arg))
+
+	case TIOCHWCSECHO:
+		if (get_user (tmp.echo, (ioctl_echo_t *) arg))
 			goto fault;
 		break;
-	   
-	   case TIOCHWCSCOLS :
-                if (get_user(tmp.columns, (ioctl_cols_t *) arg))
+
+	case TIOCHWCSCOLS:
+		if (get_user (tmp.columns, (ioctl_cols_t *) arg))
 			goto fault;
 		break;
-	   
-	   case TIOCHWCSCODE :
-                if (get_user(tmp.code, (ioctl_code_t *) arg))
+
+	case TIOCHWCSCODE:
+		if (get_user (tmp.code, (ioctl_code_t *) arg))
 			goto fault;
 
 		break;
-	   
-	   case TIOCHWCSNL :
-                if (get_user(tmp.final_nl, (ioctl_nl_t *) arg))
+
+	case TIOCHWCSNL:
+		if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCSOBUF :
-                if (get_user(obuf, (unsigned int *) arg))
+	case TIOCHWCSOBUF:
+		if (get_user (obuf, (unsigned int *) arg))
 			goto fault;
 		if (obuf & 0xFFF)
 			tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12);
@@ -2061,93 +2084,108 @@
 			tmp.max_hwcb = (obuf >> 12);
 		break;
 
-	   case TIOCHWCSCASE :
-                if (get_user(tmp.tolower, (ioctl_case_t *) arg))
+	case TIOCHWCSCASE:
+		if (get_user (tmp.tolower, (ioctl_case_t *) arg))
 			goto fault;
 		break;
-	   
-	   case TIOCHWCSDELIM :
-		if (get_user(tmp.delim, (ioctl_delim_t *) arg))
+
+	case TIOCHWCSDELIM:
+		if (get_user (tmp.delim, (ioctl_delim_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCSINIT :
-		retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1);
+	case TIOCHWCSINIT:
+		retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
 		break;
 
-	   case TIOCHWCGHTAB :
-		if (put_user(tmp.width_htab, (ioctl_htab_t *) arg))
+	case TIOCHWCGMEASL:
+		if (put_user (tmp.measured_lines, (ioctl_meas_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCGECHO :
-                if (put_user(tmp.echo, (ioctl_echo_t *) arg))
+	case TIOCHWCGMEASC:
+		if (put_user (tmp.measured_chars, (ioctl_meas_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCGCOLS :
-                if (put_user(tmp.columns, (ioctl_cols_t *) arg))
+	case TIOCHWCGMEASS:
+		if (put_user (tmp.measured_wcalls, (ioctl_meas_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCGCODE :
-                if (put_user(tmp.code, (ioctl_code_t *) arg))
+	case TIOCHWCGHTAB:
+		if (put_user (tmp.width_htab, (ioctl_htab_t *) arg))
 			goto fault;
+		break;
 
+	case TIOCHWCGECHO:
+		if (put_user (tmp.echo, (ioctl_echo_t *) arg))
+			goto fault;
 		break;
 
-	   case TIOCHWCGNL :
-                if (put_user(tmp.final_nl, (ioctl_nl_t *) arg))
+	case TIOCHWCGCOLS:
+		if (put_user (tmp.columns, (ioctl_cols_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCGOBUF :
-                if (put_user(tmp.max_hwcb, (ioctl_obuf_t *) arg))
+	case TIOCHWCGCODE:
+		if (put_user (tmp.code, (ioctl_code_t *) arg))
 			goto fault;
+
 		break;
 
-	   case TIOCHWCGKBUF :
-                if (put_user(tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
+	case TIOCHWCGNL:
+		if (put_user (tmp.final_nl, (ioctl_nl_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCGCASE :
-                if (put_user(tmp.tolower, (ioctl_case_t *) arg))
+	case TIOCHWCGOBUF:
+		if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg))
 			goto fault;
 		break;
-	   
-	   case TIOCHWCGDELIM :
-		if (put_user(tmp.delim, (ioctl_delim_t *) arg))
+
+	case TIOCHWCGKBUF:
+		if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
 			goto fault;
 		break;
-#if 0 
-	   
-	   case TIOCHWCGINIT :
-		if (put_user(&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
+
+	case TIOCHWCGCASE:
+		if (put_user (tmp.tolower, (ioctl_case_t *) arg))
 			goto fault;
 		break;
 
-	   case TIOCHWCGCURR :
-		if (put_user(&hwc_data.ioctls, (hwc_ioctls_t *) arg))
+	case TIOCHWCGDELIM:
+		if (put_user (tmp.delim, (ioctl_delim_t *) arg))
+			goto fault;
+		break;
+#if 0
+
+	case TIOCHWCGINIT:
+		if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
+			goto fault;
+		break;
+
+	case TIOCHWCGCURR:
+		if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg))
 			goto fault;
 		break;
 #endif
-	   
-	   default :
+
+	default:
 		goto noioctlcmd;
 	}
 
-	if (_IOC_DIR(cmd) == _IOC_WRITE)
-		retval = set_hwc_ioctls(&tmp, 0);
+	if (_IOC_DIR (cmd) == _IOC_WRITE)
+		retval = set_hwc_ioctls (&tmp, 0);
 
 	goto out;
 
-	fault:
-		retval = -EFAULT;
-		goto out;
-	noioctlcmd:
-		retval = -ENOIOCTLCMD;
-	out:
-		spin_unlock_irqrestore(&hwc_data.lock, flags);
-		return retval;
+      fault:
+	retval = -EFAULT;
+	goto out;
+      noioctlcmd:
+	retval = -ENOIOCTLCMD;
+      out:
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
+	return retval;
 }
diff -urN linux-2.2.18-pre20/drivers/s390/char/hwc_rw.h linux/drivers/s390/char/hwc_rw.h
--- linux-2.2.18-pre20/drivers/s390/char/hwc_rw.h	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/char/hwc_rw.h	Mon Dec  3 22:14:17 2001
@@ -31,6 +31,7 @@
 typedef unsigned short int ioctl_obuf_t;
 typedef unsigned char ioctl_case_t;
 typedef unsigned char ioctl_delim_t;
+typedef unsigned long ioctl_meas_t;
 
 typedef struct {
 	ioctl_htab_t width_htab;
@@ -39,9 +40,12 @@
 	ioctl_code_t code;
 	ioctl_nl_t final_nl;
 	ioctl_obuf_t max_hwcb;
-	ioctl_obuf_t kmem_hwcb;		
+	ioctl_obuf_t kmem_hwcb;
 	ioctl_case_t tolower;
 	ioctl_delim_t delim;
+	ioctl_meas_t measured_lines;
+	ioctl_meas_t measured_chars;
+	ioctl_meas_t measured_wcalls;
 } hwc_ioctls_t;
 
 static hwc_ioctls_t _hwc_ioctls;
@@ -64,6 +68,8 @@
 
 #define TIOCHWCSCASE	_IOW(HWC_IOCTL_LETTER, 7, _hwc_ioctls.tolower)
 
+#define TIOCHWCSMEAS	_IO(HWC_IOCTL_LETTER, 8)
+
 #define TIOCHWCSDELIM	_IOW(HWC_IOCTL_LETTER, 9, _hwc_ioctls.delim)
 
 #define TIOCHWCGHTAB	_IOR(HWC_IOCTL_LETTER, 10, _hwc_ioctls.width_htab)
@@ -82,11 +88,17 @@
 
 #define TIOCHWCGCASE	_IOR(HWC_IOCTL_LETTER, 17, _hwc_ioctls.tolower)
 
-#define TIOCHWCGDELIM	_IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.delim)
+#define TIOCHWCGDELIM	_IOR(HWC_IOCTL_LETTER, 18, _hwc_ioctls.delim)
+
+#define TIOCHWCGKBUF	_IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.max_hwcb)
+
+#define TIOCHWCGCURR	_IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls)
 
-#define TIOCHWCGKBUF	_IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls.max_hwcb)
+#define TIOCHWCGMEASL	_IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls.measured_lines)
 
-#define TIOCHWCGCURR	_IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls)
+#define TIOCHWCGMEASC  _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars)
+
+#define TIOCHWCGMEASS	_IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls)
 
 #define CODE_ASCII              0x0
 #define CODE_EBCDIC             0x1
@@ -117,4 +129,4 @@
 
 #endif
 
-#endif   
+#endif
diff -urN linux-2.2.18-pre20/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c
--- linux-2.2.18-pre20/drivers/s390/char/hwc_tty.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/char/hwc_tty.c	Mon Dec  3 22:14:17 2001
@@ -43,22 +43,22 @@
 static hwc_tty_data_struct hwc_tty_data =
 { /* NULL/0 */ };
 static struct tty_driver hwc_tty_driver;
-static struct tty_struct * hwc_tty_table[1];
-static struct termios * hwc_tty_termios[1];
-static struct termios * hwc_tty_termios_locked[1];
+static struct tty_struct *hwc_tty_table[1];
+static struct termios *hwc_tty_termios[1];
+static struct termios *hwc_tty_termios_locked[1];
 static int hwc_tty_refcount = 0;
 
-extern struct termios  tty_std_termios;
+extern struct termios tty_std_termios;
 
 void hwc_tty_wake_up (void);
 void hwc_tty_input (unsigned char *, unsigned int);
 
 static int 
 hwc_tty_open (struct tty_struct *tty,
-                         struct file       *filp)
+	      struct file *filp)
 {
 
-	if (MINOR(tty->device) - tty->driver.minor_start)
+	if (MINOR (tty->device) - tty->driver.minor_start)
 		return -ENODEV;
 
 	tty->driver_data = &hwc_tty_data;
@@ -75,10 +75,10 @@
 
 static void 
 hwc_tty_close (struct tty_struct *tty,
-                           struct file *filp)
+	       struct file *filp)
 {
-	if (MINOR(tty->device) != tty->driver.minor_start) {
-		printk(KERN_WARNING HWC_TTY_PRINT_HEADER
+	if (MINOR (tty->device) != tty->driver.minor_start) {
+		printk (KERN_WARNING HWC_TTY_PRINT_HEADER
 			"do not close hwc tty because of wrong device number");
 		return;
 	}
@@ -95,40 +95,40 @@
 {
 	int retval;
 
-	retval = hwc_write_room(IN_BUFS_TOTAL);
+	retval = hwc_write_room (IN_BUFS_TOTAL);
 	return retval;
 }
 
 static int 
 hwc_tty_write (struct tty_struct *tty,
-			  int                  from_user,
-	                  const unsigned char *buf,
-       		          int                  count)
+	       int from_user,
+	       const unsigned char *buf,
+	       int count)
 {
 	int retval;
 
 	if (hwc_tty_data.buf_count > 0) {
-		hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+		hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
 		hwc_tty_data.buf_count = 0;
 	}
-	retval = hwc_write(from_user, buf, count);
+	retval = hwc_write (from_user, buf, count);
 	return retval;
 }
 
 static void 
 hwc_tty_put_char (struct tty_struct *tty,
-                              unsigned char ch)
+		  unsigned char ch)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&hwc_tty_data.lock, flags);
+	spin_lock_irqsave (&hwc_tty_data.lock, flags);
 	if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE) {
-		hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+		hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
 		hwc_tty_data.buf_count = 0;
 	}
 	hwc_tty_data.buf[hwc_tty_data.buf_count] = ch;
 	hwc_tty_data.buf_count++;
-	spin_unlock_irqrestore(&hwc_tty_data.lock, flags);
+	spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
 }
 
 static void 
@@ -136,10 +136,10 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&hwc_tty_data.lock, flags);
-	hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+	spin_lock_irqsave (&hwc_tty_data.lock, flags);
+	hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
 	hwc_tty_data.buf_count = 0;
-	spin_unlock_irqrestore(&hwc_tty_data.lock, flags);
+	spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
 }
 
 static int 
@@ -147,7 +147,7 @@
 {
 	int retval;
 
-	retval = hwc_chars_in_buffer(IN_BUFS_TOTAL);
+	retval = hwc_chars_in_buffer (IN_BUFS_TOTAL);
 	return retval;
 }
 
@@ -159,15 +159,15 @@
 
 static int 
 hwc_tty_ioctl (
-	struct tty_struct *tty,
-	struct file * file,
-	unsigned int cmd,
-	unsigned long arg)
+		      struct tty_struct *tty,
+		      struct file *file,
+		      unsigned int cmd,
+		      unsigned long arg)
 {
 	unsigned long count;
 
-        if (tty->flags & (1 << TTY_IO_ERROR))
-                return -EIO;
+	if (tty->flags & (1 << TTY_IO_ERROR))
+		return -EIO;
 
 	switch (cmd) {
 	case TIOCHWCTTYSINTRC:
@@ -186,8 +186,8 @@
 				     (long) hwc_tty_data.ioctl.intr_char_size);
 
 	default:
-	return hwc_ioctl(cmd, arg);
-}
+		return hwc_ioctl (cmd, arg);
+	}
 }
 
 void 
@@ -256,22 +256,22 @@
 			     hwc_tty_data.ioctl.intr_char_size) == 0) {
 			tty->flip.count++;
 			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-			*tty->flip.char_buf_ptr++ = INTR_CHAR(tty);
+			*tty->flip.char_buf_ptr++ = INTR_CHAR (tty);
 		} else if (count == 2 && (
 						 strncmp (buf, "^d", 2) == 0 ||
 					   strncmp (buf, "\0252d", 2) == 0)) {
 			tty->flip.count++;
 			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-			*tty->flip.char_buf_ptr++ = EOF_CHAR(tty);
+			*tty->flip.char_buf_ptr++ = EOF_CHAR (tty);
 		} else if (count == 2 && (
 						 strncmp (buf, "^z", 2) == 0 ||
 					   strncmp (buf, "\0252z", 2) == 0)) {
 			tty->flip.count++;
 			*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-			*tty->flip.char_buf_ptr++ = SUSP_CHAR(tty);
+			*tty->flip.char_buf_ptr++ = SUSP_CHAR (tty);
 		} else {
 
-			memcpy(tty->flip.char_buf_ptr, buf, count);
+			memcpy (tty->flip.char_buf_ptr, buf, count);
 			if (count < 2 || (
 					 strncmp (buf + count - 2, "^n", 2) ||
 				    strncmp (buf + count - 2, "\0252n", 2))) {
@@ -279,12 +279,12 @@
 				count++;
 			} else
 				count -= 2;
-			memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
+			memset (tty->flip.flag_buf_ptr, TTY_NORMAL, count);
 			tty->flip.char_buf_ptr += count;
 			tty->flip.flag_buf_ptr += count;
 			tty->flip.count += count;
 		}
-		tty_flip_buffer_push(tty);
+		tty_flip_buffer_push (tty);
 		hwc_tty_wake_up ();
 	}
 #endif
@@ -293,7 +293,7 @@
 void 
 hwc_tty_init (void)
 {
-	memset (&hwc_tty_driver, 0, sizeof(struct tty_driver));
+	memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
 	memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
 	hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
 	hwc_tty_driver.driver_name = "tty_hwc";
@@ -310,7 +310,7 @@
 	hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO;
 	hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW;
 	hwc_tty_driver.refcount = &hwc_tty_refcount;
-	
+
 	hwc_tty_driver.table = hwc_tty_table;
 	hwc_tty_driver.termios = hwc_tty_termios;
 	hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
@@ -324,20 +324,20 @@
 	hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer;
 	hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer;
 	hwc_tty_driver.ioctl = hwc_tty_ioctl;
-	
+
 	hwc_tty_driver.throttle = NULL;
 	hwc_tty_driver.unthrottle = NULL;
 	hwc_tty_driver.send_xchar = NULL;
 	hwc_tty_driver.set_termios = NULL;
 	hwc_tty_driver.set_ldisc = NULL;
-	hwc_tty_driver.stop = NULL; 
-	hwc_tty_driver.start = NULL; 
+	hwc_tty_driver.stop = NULL;
+	hwc_tty_driver.start = NULL;
 	hwc_tty_driver.hangup = NULL;
 	hwc_tty_driver.break_ctl = NULL;
 	hwc_tty_driver.wait_until_sent = NULL;
 	hwc_tty_driver.read_proc = NULL;
 	hwc_tty_driver.write_proc = NULL;
 
-	if (tty_register_driver(&hwc_tty_driver))
-		panic("Couldn't register hwc_tty driver\n");
+	if (tty_register_driver (&hwc_tty_driver))
+		panic ("Couldn't register hwc_tty driver\n");
 }
diff -urN linux-2.2.18-pre20/drivers/s390/idals.c linux/drivers/s390/idals.c
--- linux-2.2.18-pre20/drivers/s390/idals.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/idals.c	Mon Dec  3 22:14:17 2001
@@ -0,0 +1,79 @@
+/* 
+   * File...........: linux/drivers/s390x/idals.c
+   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+   * Bugreports.to..: <Linux390@de.ibm.com>
+   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+   
+   * History of changes
+   * 07/24/00 new file
+ */
+
+#include <linux/malloc.h>
+#include <asm/irq.h>
+#include <asm/idals.h>
+#include <asm/spinlock.h>
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif
+#define PRINTK_HEADER "idals:"
+
+/* a name template for the cache-names */
+static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */
+/* the cache's names */
+static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; 
+/* the caches itself*/
+static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; 
+
+void
+free_idal ( ccw1_t *cp )
+{
+	idaw_t *idal;
+	unsigned long upper2k,lower2k;
+	int nridaws,cacheind;
+	if ( cp -> flags & CCW_FLAG_IDA ) {
+		idal = cp -> cda;
+		lower2k = *idal & 0xfffffffffffff800;
+		upper2k = (*idal  + cp -> count - 1) & 0xfffffffffffff800;
+		nridaws = ((upper2k - lower2k) >> 11) + 1;
+		for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ );
+		kmem_cache_free ( idal_cache[cacheind], idal );
+	}
+}
+
+int 
+idal_support_init ( void ) 
+{
+	int rc=0;
+	int cachind;
+	
+	for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
+		int slabsize = 8 << cachind;
+		sprintf ( idal_cache_name[cachind], 
+			  "%s%d%c", idal_name_template, slabsize, 0);
+		idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], 
+							 slabsize, 0,
+							 SLAB_HWCACHE_ALIGN | SLAB_DMA, 
+							 NULL, NULL );
+		if ( ! idal_cache [cachind] ) {
+			printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n");
+		}
+	}
+	
+	return rc;
+}
+
+void idal_support_cleanup ( void )
+{
+	int cachind;
+
+	/* Shrink the caches, if available */
+	for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
+		if ( idal_cache[cachind] ) {
+			if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) {
+				idal_cache[cachind] = NULL;
+			}
+		}
+	}
+
+}
diff -urN linux-2.2.18-pre20/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile
--- linux-2.2.18-pre20/drivers/s390/net/Makefile	Tue Jan  4 10:12:18 2000
+++ linux/drivers/s390/net/Makefile	Mon Dec  3 22:14:17 2001
@@ -7,6 +7,10 @@
 
 ifeq ($(CONFIG_CTC),y)
   O_OBJS += ctc.o
+else
+  ifeq ($(CONFIG_CTC),m)
+  M_OBJS += ctc.o
+  endif
 endif
 
 ifeq ($(CONFIG_IUCV),y)
diff -urN linux-2.2.18-pre20/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- linux-2.2.18-pre20/drivers/s390/net/ctc.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/net/ctc.c	Mon Dec  3 22:14:17 2001
@@ -1,4 +1,6 @@
 /*
+ * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $
+ *
  *  drivers/s390/net/ctc.c 
  *    CTC / ESCON network driver
  *
@@ -7,7 +9,11 @@
  *    Author(s): Dieter Wellerdiek (wel@de.ibm.com)
  *
  *     2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com)
- *                 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *		   Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ *     Modularization & Bugfixes by Fritz Elfert (fritz.elfert@millenux.de)
+ *
+ *     Bugfixes by Jochen Röhrig (roehrig@de.ibm.com)
  *
  *
  *  Description of the Kernel Parameter
@@ -16,50 +22,142 @@
  *    order or doesn't want to have automatic channel selection on, you can do 
  *    this with the "ctc= kernel keyword". 
  *
- *       ctc=0,0xrrrr,0xwwww,ddddd
+ *	 ctc=0,0xrrrr,0xwwww,ddddd
  *
  *     Where:
  *
- *       "rrrr" is the read channel address
- *       "wwww" is the write channel address
- *       "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
- *              to escon7 for ESCON channels).
+ *	 "rrrr" is the read channel address
+ *	 "wwww" is the write channel address
+ *	 "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
+ *		to escon7 for ESCON channels).
  *
  *     To switch the automatic channel selection off use the ctc= keyword with 
  *     parameter "noauto". This may be necessary if you 3271 devices or other devices 
  *     which use the ctc device type and model, but operate with a different protocol. 
  *     
- *       ctc=noauto
+ *	 ctc=noauto
+ * 
+ * $Log: ctc.c,v $
+ * Revision 1.25.2.5  2000/10/11 15:08:59  bird
+ * ctc_tx(): Quick fix of possible underflow when calculating free block space
+ *
+ * Revision 1.25.2.4  2000/09/25 16:40:56  bird
+ * Some more debug information
+ *
+ * Revision 1.25.2.3  2000/09/20 13:28:19  bird
+ * - ctc_open(): fixed bug
+ * - ctc_release(): added timer for terminating in case of halt_io()-hang
+ *
+ * Revision 1.25.2.2  2000/09/20 09:48:27  bird
+ * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
+ *   instead of direct waiting on a wait queue
+ * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
+ *   print more debug information
+ *
+ * Revision 1.25.2.1  2000/09/19 09:09:56  bird
+ * Merged in changes from 1.25 to 1.26
+ *
+ * Revision 1.25  2000/09/08 09:22:11  bird
+ * Proper cleanup and bugfixes in ctc_probe()
+ *
+ * Revision 1.24  2000/08/30 15:14:38  bird
+ * Some bugfixes and simplifications in ctc_probe()
+ *
+ * Revision 1.23  2000/08/28 16:50:35  bird
+ * - Suppress warning if discarding initial handshake block
+ * - Removed strstr() (now exported in arch/s390/kernel/s390_ksyms.c)
+ *
+ * Revision 1.22  2000/08/28 11:33:21  felfert
+ * Remove some dead code in ctc_open().
+ *
+ * Revision 1.21  2000/08/28 09:31:06  bird
+ * init_module(): fixed pointer arithmetic (device name)
+ *
+ * Revision 1.20  2000/08/25 20:11:56  bird
+ * Didn´t build as non-module.
+ *
+ * Revision 1.19  2000/08/25 19:48:46  felfert
+ * Modularized version.
+ *
+ * Revision 1.18  2000/08/25 19:34:29  bird
+ * extract_channel_id():
+ *  - check for valid channel id;
+ *    return -EINVAL in case of violation
+ *
+ * ctc_setup():
+ *  - check for valid channel id;
+ *    return without doing anything in case of violation
+ *
+ * ctc_irq_bh():
+ *  - check for valid block length and packet length;
+ *    discard block in case of invalid values
+ *    (solves infinite loop problem that occurs if (for some unknown reason)
+ *    the packet length = 0)
+ *
+ * Revision 1.17  2000/08/25 09:22:51  bird
+ * ctc_buffer_alloc():
+ *   fixed kmalloc()-bug (allocated buffer of wrong size)
+ *
+ * Revision 1.16  2000/08/24 17:46:19  bird
+ * ctc_write_retry():
+ *  - removed (presumably useless) loop for cleaning up the proc_anchor list.
+ *  - inserted warning if proc_anchor (unexpectedly) != NULL
+ *
+ * Revision 1.15  2000/08/24 15:25:04  bird
+ * ctc_read_retry():
+ *  - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set
+ *  - removed some useless debug-messages
+ * ctc_write_retry():
+ *  - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set
+ *
+ * Revision 1.14  2000/08/24 09:34:47  felfert
+ * Fixed bug in ctc_release:
+ *  - ctc_unprotect_busy_irqrestore was called with wrong parameter.
+ *
  *
- *  Change History
+ * Old Change History
  *    0.50  Initial release shipped
  *    0.51  Bug fixes
- *          - CTC / ESCON network device can now handle up to 64 channels 
- *          - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON 
- *          - 3088-62 info message suppressed - OSA/D   
- *          - channel: def ffffffed ... error message suppressed 
- *          - CTC / ESCON device was not recoverable after a lost connection with 
- *            IFCONFIG dev DOWN and IFCONFIG dev UP 
- *          - Possibility to switch the automatic selection off
- *          - Minor bug fixes 
+ *	    - CTC / ESCON network device can now handle up to 64 channels 
+ *	    - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON 
+ *	    - 3088-62 info message suppressed - OSA/D	
+ *	    - channel: def ffffffed ... error message suppressed 
+ *	    - CTC / ESCON device was not recoverable after a lost connection with 
+ *	      IFCONFIG dev DOWN and IFCONFIG dev UP 
+ *	    - Possibility to switch the automatic selection off
+ *	    - Minor bug fixes
  *    0.52  Bug fixes 
- *          - Subchannel check message enhanced 
- *          - Read / Write retry routine check for CTC_STOP added  
+ *	    - Subchannel check message enhanced 
+ *	    - Read / Write retry routine check for CTC_STOP added 
  *    0.53  Enhancement 
- *          - Connect time changed from 150 to 300 seconds
- *            This gives more a better chance to connect during IPL 
+ *	    - Connect time changed from 150 to 300 seconds
+ *	      This gives more a better chance to connect during IPL 
  *    0.54  Bug fixes 
- *          - Out of memory message enhanced 
- *          - Zero buffer problem in ctc_irq_hb solved
- *            A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
- *            which could end in a out of memory situation.  
+ *	    - Out of memory message enhanced 
+ *	    - Zero buffer problem in ctc_irq_hb solved
+ *	      A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
+ *	      which could end in a out of memory situation.  
  *    0.55  Bug fixes 
- *          - Connect problems with systems which IPL later
- *            SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
- *            not available. When systemB comes up it is nearly inpossible to setup a 
- *            connection.  
+ *	    - Connect problems with systems which IPL later
+ *	      SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
+ *	      not available. When systemB comes up it is nearly inpossible to setup a 
+ *	      connection.  
+ *
+ *    0.56  Bug fixes 
+ *	    - ctc_open(): In case of failure stop read/write-retry timers before
+ *           freeing buffers (stops kernel panics due to NULL-pointer
+ *           dereferences in ctc_read_retry())
+ *      - Added some sanity checks concerning NULL-pointer dereferences
+ *      - Added some comments
+ *
+ *    0.57  Bug fixes
+ *	    - CTC / ESCON network device can now handle up to 256 channels 
+ *      - ctc_read_retry(): added sanity check: if ctc->free_anchor == NULL
+ *                          print a warning and simply return
  */
+
 #include <linux/version.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
@@ -78,6 +176,7 @@
 #include <linux/if_arp.h>
 #include <linux/tcp.h>
 #include <linux/skbuff.h>
+#include <linux/ctype.h>
 
 #include <asm/io.h>
 #include <asm/bitops.h>
@@ -85,56 +184,67 @@
 #include <asm/irq.h>
 
 
+#ifdef MODULE
+MODULE_AUTHOR("(C) 2000 IBM Corp. by Dieter Wellerdiek (wel@de.ibm.com)");
+MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+MODULE_PARM(setup,"s");
+MODULE_PARM_DESC(setup,
+"One or more definitions in the same format like the kernel parameter line for ctc.\n"
+"E.g.: \"ctc=0,0x700,0x701,ctc0 ctc=0,0x702,0x703,ctc1\".\n");
+
+char *setup = NULL;
+#endif
+
 //#define DEBUG 
 
 /* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */
-#ifdef DEBUG                
-        #undef  KERN_INFO
-        #undef  KERN_WARNING
-        #undef  KERN_DEBUG
-        #define KERN_INFO    KERN_EMERG
-        #define KERN_WARNING KERN_EMERG
-        #define KERN_DEBUG   KERN_EMERG
-#endif  
-
-
-#define CCW_CMD_WRITE           0x01
-#define CCW_CMD_READ            0x02
-#define CCW_CMD_SET_EXTENDED    0xc3
-#define CCW_CMD_PREPARE         0xe3
-
-#define MAX_CHANNEL_DEVICES     64 
-#define MAX_ADAPTERS            8
-#define CTC_DEFAULT_MTU_SIZE    1500
-#define READ                    0
-#define WRITE                   1
-#define CTC                     0
-#define ESCON                   1
-#define CHANNEL_MEDIA           2
-#define CTC_BLOCKS              8          /* 8 blocks * 2 times * 64k = 1M */
-
-#define TB_TX                   0          /* sk buffer handling in process */
-#define TB_STOP                 1          /* network device stop in process */
-#define TB_RETRY                2          /* retry in process */
-#define TB_NOBUFFER             3          /* no buffer on free queue */ 
+#ifdef DEBUG		    
+	#undef	KERN_INFO
+	#undef	KERN_WARNING
+	#undef	KERN_DEBUG
+	#define KERN_INFO    KERN_EMERG
+	#define KERN_WARNING KERN_EMERG
+	#define KERN_DEBUG   KERN_EMERG
+#endif	
+
+
+#define CCW_CMD_WRITE		0x01
+#define CCW_CMD_READ		0x02
+#define CCW_CMD_SET_EXTENDED	0xc3
+#define CCW_CMD_PREPARE		0xe3
+
+#define MAX_CHANNEL_DEVICES	256 
+#define MAX_ADAPTERS		8
+#define CTC_DEFAULT_MTU_SIZE	1500
+#define READ			0
+#define WRITE			1
+#define CTC			0
+#define ESCON			1
+#define CHANNEL_MEDIA		2
+#define CTC_BLOCKS		8	   /* 8 blocks * 2 times * 64k = 1M */
+
+#define TB_TX			0	   /* sk buffer handling in process */
+#define TB_STOP			1	   /* network device stop in process */
+#define TB_RETRY		2	   /* retry in process */
+#define TB_NOBUFFER		3	   /* no buffer on free queue */ 
 
 /* state machine codes used in ctc_irq_handler */
-#define CTC_STOP                0
-#define CTC_START_HALT_IO       1
-#define CTC_START_SET_X_MODE    2
-#define CTC_START_SELECT        4 
-#define CTC_START_READ_TEST     32
-#define CTC_START_READ          33
-#define CTC_START_WRITE_TEST    64
-#define CTC_START_WRITE         65
+#define CTC_STOP		0
+#define CTC_START_HALT_IO	1
+#define CTC_START_SET_X_MODE	2
+#define CTC_START_SELECT	4 
+#define CTC_START_READ_TEST	32
+#define CTC_START_READ		33
+#define CTC_START_WRITE_TEST	64
+#define CTC_START_WRITE		65
 
 
 typedef enum { 
-        channel_type_none,           /* Device is not a channel */
-        channel_type_undefined,      /* Device is a channel but we don't know anything about it */
-        channel_type_ctca,           /* Device is a CTC/A and we can deal with it */
-        channel_type_escon,          /* Device is a ESCON channel and we can deal with it */
-        channel_type_unsupported     /* Device is a unsupported model */
+	channel_type_none,	     /* Device is not a channel */
+	channel_type_undefined,	     /* Device is a channel but we don't know anything about it */
+	channel_type_ctca,	     /* Device is a CTC/A and we can deal with it */
+	channel_type_escon,	     /* Device is a ESCON channel and we can deal with it */
+	channel_type_unsupported     /* Device is a unsupported model */
 } channel_type_t; 
   
 
@@ -144,30 +254,39 @@
  *
  */  
 
-static int channel_tab_initialized = 0;     /* channel[] structure initialized */
+static long channel_tab_initialized = 0;	    /* channel[] structure initialized */
 
 struct devicelist {  
-        unsigned int  devno;
-        __u8          flag;
-#define CHANNEL_IN_USE   0x08               /* - Show that channel is in use */
+	unsigned int  devno;
+	__u8	      flag;
+#define CHANNEL_IN_USE	 0x08		    /* - Show that channel is in use */
 }; 
 
 static struct {
-        struct devicelist  list[MAX_CHANNEL_DEVICES]; 
-        int                count;
-        int                left;
+	struct devicelist  list[MAX_CHANNEL_DEVICES]; 
+	int		   count;
+	int		   left;
 } channel[CHANNEL_MEDIA];
 
 
 
 static int ctc_no_auto = 0;
 
+#if LINUX_VERSION_CODE>=0x020300
+typedef struct net_device  net_device;
+#else
+typedef struct device  net_device;
+typedef struct wait_queue* wait_queue_head_t;
+#define init_waitqueue_head(nothing)
+#endif
+
 struct adapterlist{ 
-        unsigned int       devno[2];
-        __u16              protocol;
+	unsigned int	   devno[2];
+	__u16		   protocol;
+	net_device         *netdev;
 };
 
-static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS];  /* 0 = CTC  / 1 = ESCON */
+static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS];  /* 0 = CTC	 / 1 = ESCON */
 
 
 /* 
@@ -176,51 +295,43 @@
  */
     
 struct buffer {
-        struct buffer       *next;
-        int                 packets;
-        struct block        *block;
+	struct buffer	    *next;
+	int		    packets;
+	struct block	    *block;
 };
 
-#if LINUX_VERSION_CODE>=0x020300
-typedef struct net_device  net_device;
-#else
-typedef struct device  net_device;
-typedef struct wait_queue* wait_queue_head_t;
-#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue  waitqname = {waitqtask, NULL }
-#define init_waitqueue_head(nothing)
-#endif
-
-
 struct channel {
-        unsigned int        devno;
-        int                 irq;
-        unsigned long       IO_active;
-        ccw1_t              ccw[3];
-        __u32               state; 
-        int                 buffer_count;
-        struct buffer       *free_anchor;
-        struct buffer       *proc_anchor;
-        devstat_t           *devstat;
-        net_device   *dev;      /* backward pointer to the network device */ 
+	unsigned int	    devno;
+	int		    irq;
+	unsigned long	    IO_active;
+	ccw1_t		    ccw[3];
+	__u32		    state; 
+	int		    buffer_count;
+	struct buffer	    *free_anchor;
+	struct buffer	    *proc_anchor;
+	devstat_t	    *devstat;
+	net_device   *dev;	/* backward pointer to the network device */ 
 	wait_queue_head_t   wait;
-        struct tq_struct    tq;
-        struct timer_list   timer;
-        unsigned long       flag_a;    /* atomic flags */
-#define CTC_BH_ACTIVE       0   
-        __u8                last_dstat;
-        __u8                flag;
-#define CTC_WRITE            0x01      /* - Set if this is a write channel */
-#define CTC_TIMER            0x80      /* - Set if timer made the wake_up  */ 
+	struct tq_struct    tq;
+	int		    initial_block_received; /* only used for read channel */
+	struct timer_list   timer;
+	unsigned long	    flag_a;    /* atomic flags */
+#define CTC_BH_ACTIVE	    0	
+	__u8		    last_dstat;
+	__u8		    flag;
+#define CTC_WRITE      0x01      /* - Set if this is a write channel */
+#define CTC_WAKEUP     0x02      /* - Set if this channel should wake up from waiting for an event */
+#define CTC_TIMER      0x80      /* - Set if timer made the wake_up  */ 
 };
 
 
-struct ctc_priv {                                                                    
-        struct net_device_stats  stats;
+struct ctc_priv {								     
+	struct net_device_stats	 stats;
 #if LINUX_VERSION_CODE>=0x02032D
-	int                      tbusy;
+	unsigned long		 tbusy;
 #endif
-        struct channel           channel[2]; 
-        __u16                    protocol;
+	struct channel		 channel[2]; 
+	__u16			 protocol;
 };  
 
 /*
@@ -230,16 +341,16 @@
 
 #define PACKET_HEADER_LENGTH  6
 struct packet {
-        __u16         length;
-        __u16         type;
-        __u16         unused;
-        __u8          data;
+	__u16	      length;
+	__u16	      type;
+	__u16	      unused;
+	__u8	      data;
 }; 
 
 #define BLOCK_HEADER_LENGTH   2
 struct block {
-        __u16         length;
-        struct packet data;
+	__u16	      length;
+	struct packet data;
 };
 
 #if LINUX_VERSION_CODE>=0x02032D
@@ -275,7 +386,7 @@
 static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
 {
 	set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy));
-	netif_stop_queue(dev);	
+	netif_stop_queue(dev);	    
 }
 
 static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
@@ -318,17 +429,17 @@
 
 static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
 {
-	set_bit(nr,(void *)&dev->tbusy);
+	set_bit(nr,&dev->tbusy);
 }
 
 static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
 {
-	clear_bit(nr,(void *)&dev->tbusy);
+	clear_bit(nr,&dev->tbusy);
 }
 
 static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev)
 {
-	return(test_and_set_bit(nr,(void *)&dev->tbusy));
+	return(test_and_set_bit(nr,&dev->tbusy));
 }
 #endif
 
@@ -338,9 +449,9 @@
 
 /* Interrupt handler */
 static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs);
-static void ctc_irq_bh(struct channel *ctc); 
-static void ctc_read_retry (struct channel *ctc);
-static void ctc_write_retry (struct channel *ctc);
+static void ctc_irq_bh(void *data); 
+static void ctc_read_retry (unsigned long data);
+static void ctc_write_retry (unsigned long data);
 
 
 /* Functions for the DEV methods */
@@ -348,7 +459,7 @@
  
 
 static int ctc_open(net_device *dev); 
-static void ctc_timer (struct channel *ctc);
+static void ctc_timer (unsigned long data);
 static int ctc_release(net_device *dev);
 static int ctc_tx(struct sk_buff *skb, net_device *dev);
 static int ctc_change_mtu(net_device *dev, int new_mtu);
@@ -370,35 +481,55 @@
 
 
 /*
+ * misc.
+ */
+static void print_banner(void) {
+	static int printed = 0;
+	char vbuf[] = "$Revision: 1.25.2.5 $";
+	char *version = vbuf;
+
+	if (printed)
+		return;
+	if ((version = strchr(version, ':'))) {
+		char *p = strchr(version + 1, '$');
+		if (p)
+			*p = '\0';
+	} else
+		version = " ??? ";
+	printk(KERN_INFO "CTC driver Version%s initialized\n", version);
+	printed = 1;
+}
+
+/*
  * initialize the channel[].list 
  */   
 static void channel_init(void) 
 {
-        int     m;
+	int	m;
 #ifdef DEBUG
-        int     c;
+	int	c;
 #endif
 
-        if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){
-                channel_scan(); 
-                for (m = 0; m < CHANNEL_MEDIA; m++) { 
-                        channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); 
-                        channel[m].left = channel[m].count;   
-                }
-                if (channel[CTC].count == 0 && channel[ESCON].count == 0) 
-                        printk(KERN_INFO "channel: no Channel devices recognized\n");
-                else
-                        printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n",
-                            channel[CTC].count, channel[ESCON].count);  
+	if (!test_and_set_bit(0, &channel_tab_initialized)){
+		channel_scan(); 
+		for (m = 0; m < CHANNEL_MEDIA; m++) { 
+			channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); 
+			channel[m].left = channel[m].count;   
+		}
+		if (channel[CTC].count == 0 && channel[ESCON].count == 0) 
+			printk(KERN_INFO "channel: no Channel devices recognized\n");
+		else
+			printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n",
+			    channel[CTC].count, channel[ESCON].count);	
 #ifdef DEBUG 
-                for (m = 0; m < CHANNEL_MEDIA;  m++) { 
-                        for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
-                                printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", 
-                                     m, c, channel[m].list[c].devno);
-                        }
-                }
+		for (m = 0; m < CHANNEL_MEDIA;	m++) { 
+			for (c = 0; c < channel[m].count; c++){
+				printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", 
+				     m, c, channel[m].list[c].devno);
+			}
+		}
 #endif
-         }
+	 }
 }
 
 
@@ -407,38 +538,37 @@
 */  
 static void channel_scan(void)
 {
-        int        m;
-        int        c;
-        int        irq;
-        dev_info_t temp;
-        
-        for (m = 0; m < CHANNEL_MEDIA;  m++) { 
-                for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
-                        channel[m].list[c].devno = -ENODEV;
-                }
-        }
-        
-        for (irq = 0; irq < NR_IRQS; irq++) {
-                /* CTC/A */
-                if (channel[CTC].count < MAX_CHANNEL_DEVICES ) {
-                        if (get_dev_info(irq, &temp) == 0 && 
-                            channel_check_for_type(&temp.sid_data) == channel_type_ctca) {
-                                channel[CTC].list[channel[CTC].count].devno = temp.devno; 
-                                channel[CTC].count++; 
-                        }
-                }
-
-                /* ESCON */
-                if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) {
-                        if (get_dev_info(irq, &temp) == 0 && 
-                            channel_check_for_type(&temp.sid_data) == channel_type_escon) {
-                                channel[ESCON].list[channel[ESCON].count].devno = temp.devno; 
-                                channel[ESCON].count++; 
-
-                        }
-                }
-        }
-} 
+	int	   m;
+	int	   c;
+	int	   irq;
+	dev_info_t temp;
+	
+	for (m = 0; m < CHANNEL_MEDIA;	m++) { 
+		for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
+			channel[m].list[c].devno = -ENODEV;
+		}
+	}
+	
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		if (get_dev_info_by_irq(irq, &temp) == 0) {
+			if ((temp.status == DEVSTAT_NOT_OPER) ||
+			    (temp.status == DEVSTAT_DEVICE_OWNED))
+				continue;
+			/* CTC/A */
+			if ((channel[CTC].count < MAX_CHANNEL_DEVICES ) &&
+			    (channel_check_for_type(&temp.sid_data) == channel_type_ctca)) {
+				channel[CTC].list[channel[CTC].count].devno = temp.devno; 
+				channel[CTC].count++; 
+			}
+			/* ESCON */
+			if ((channel[ESCON].count < MAX_CHANNEL_DEVICES ) &&
+			    (channel_check_for_type(&temp.sid_data) == channel_type_escon)) {
+				channel[ESCON].list[channel[ESCON].count].devno = temp.devno; 
+				channel[ESCON].count++; 
+			}
+		}
+	}
+}
  
 
 /*
@@ -446,17 +576,17 @@
  */  
 static int channel_free(int media, int devno)
 {
-        int     i;
+	int	i;
 
-        for (i = 0; i < channel[media].count; i++) {       
-                if ((devno == channel[media].list[i].devno) &&
-                    ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
-                        channel[media].list[i].flag &= ~CHANNEL_IN_USE;
-                        return 0;
-                }
-        }
-        printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
-        return -ENODEV; 
+	for (i = 0; i < channel[media].count; i++) {	   
+		if ((devno == channel[media].list[i].devno) &&
+		    ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
+			channel[media].list[i].flag &= ~CHANNEL_IN_USE;
+			return 0;
+		}
+	}
+	printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+	return -ENODEV; 
 }
 
 
@@ -465,17 +595,17 @@
  */  
 static int channel_get(int media, int devno)
 {
-        int     i;
+	int	i;
 
-        for (i = 0; i < channel[media].count; i++) {       
-                if ((devno == channel[media].list[i].devno) &&
-                    ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
-                        channel[media].list[i].flag |= CHANNEL_IN_USE;
-                        return channel[media].list[i].devno;             
-                }
-        }
-        printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
-        return -ENODEV; 
+	for (i = 0; i < channel[media].count; i++) {	   
+		if ((devno == channel[media].list[i].devno) &&
+		    ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
+			channel[media].list[i].flag |= CHANNEL_IN_USE;
+			return channel[media].list[i].devno;		 
+		}
+	}
+	printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+	return -ENODEV; 
 
 }
 
@@ -485,18 +615,18 @@
  */  
 static int channel_get_next(int media)
 {
-        int     i;
+	int	i;
 
-        for (i = 0; i < channel[media].count; i++) {
-                if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
+	for (i = 0; i < channel[media].count; i++) {
+		if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
 #ifdef DEBUG
-                        printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
+			printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
 #endif
-                        channel[media].list[i].flag |= CHANNEL_IN_USE;
-                        return channel[media].list[i].devno;        
-                }
-        }
-        return -ENODEV; 
+			channel[media].list[i].flag |= CHANNEL_IN_USE;
+			return channel[media].list[i].devno;	    
+		}
+	}
+	return -ENODEV; 
 }
  
 
@@ -505,7 +635,7 @@
  */  
 static int channel_left(int media)
 {
-        return channel[media].left; 
+	return channel[media].left; 
 }
 
 
@@ -514,38 +644,38 @@
  */
 static channel_type_t channel_check_for_type (senseid_t *id)
  {
-        channel_type_t type;
+	channel_type_t type;
 
-        switch (id->cu_type) {
-                case 0x3088: 
+	switch (id->cu_type) {
+		case 0x3088: 
 
-                        switch (id->cu_model) {
-                                case 0x08:    
-                                        type = channel_type_ctca;  /* 3088-08  ==> CTCA */
-                                        break; 
-
-                                case 0x1F:   
-                                        type = channel_type_escon; /* 3088-1F  ==> ESCON channel */
-                                        break;
+			switch (id->cu_model) {
+				case 0x08:    
+					type = channel_type_ctca;  /* 3088-08  ==> CTCA */
+					break; 
+
+				case 0x1F:   
+					type = channel_type_escon; /* 3088-1F  ==> ESCON channel */
+					break;
  
-                                case 0x01:                         /* 3088-01  ==> P390 OSA emulation */
-                                case 0x60:                         /* 3088-60  ==> OSA/2 adapter */
-                                case 0x61:                         /* 3088-61  ==> CISCO 7206 CLAW protocol ESCON connected */
-                                case 0x62:                         /* 3088-62  ==> OSA/D device */ 
-                                        type = channel_type_unsupported;
-                                         break; 
-
-                                default:
-                                        type = channel_type_undefined;
-                                        printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
-                        }
-                        break;
+				case 0x01:			   /* 3088-01  ==> P390 OSA emulation */
+				case 0x60:			   /* 3088-60  ==> OSA/2 adapter */
+				case 0x61:			   /* 3088-61  ==> CISCO 7206 CLAW protocol ESCON connected */
+				case 0x62:			   /* 3088-62  ==> OSA/D device */ 
+					type = channel_type_unsupported;
+					 break; 
+
+				default:
+					type = channel_type_undefined;
+					printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
+			}
+			break;
 
-                default:
-                        type = channel_type_none;
+		default:
+			type = channel_type_none;
 
-        }
-        return type;
+	}
+	return type;
 }
 
 
@@ -554,22 +684,22 @@
  */
 static void channel_sort(struct devicelist list[], int n)
 {
-        int               i;
-        int               sorted = 0;
-        struct devicelist tmp;
-
-        while (!sorted) { 
-                sorted = 1;
-
-                for (i = 0; i < n-1; i++) {  
-                        if (list[i].devno > list[i+1].devno) {  
-                                tmp = list[i];
-                                list[i] = list[i+1];
-                                list[i+1] = tmp;
-                                sorted = 0;
-                        }
-                }
-        }
+	int		  i;
+	int		  sorted = 0;
+	struct devicelist tmp;
+
+	while (!sorted) { 
+		sorted = 1;
+
+		for (i = 0; i < n-1; i++) {  
+			if (list[i].devno > list[i+1].devno) {	
+				tmp = list[i];
+				list[i] = list[i+1];
+				list[i+1] = tmp;
+				sorted = 0;
+			}
+		}
+	}
 } 
 
 
@@ -580,182 +710,216 @@
 
 static int inline extract_channel_id(char *name)
 {
-        if (name[0] == 'c') 
-                return (name[3]-'0');
-        else
-                return (name[5]-'0');
+	int rv = -1;
+	
+	if (name[0] == 'c') 
+		rv = name[3]-'0';
+	else
+		rv = name[5]-'0';
+
+	if ((rv < 0) || (rv >= MAX_ADAPTERS))
+		rv= -EINVAL;
+
+	return rv;
 }
 
 
 static int inline extract_channel_media(char *name)
 {
-        if (name[0] == 'c') 
-                return CTC;
-        else
-                return ESCON;
+	if (name[0] == 'c') 
+		return CTC;
+	else
+		return ESCON;
 }
 
 
 static void ctc_tab_init(void)
-{                                    
-        int          m;
-        int          i;
-        static int   t;
-
-        if (t == 0){
-                for (m = 0; m < CHANNEL_MEDIA;  m++) {
-                        for (i = 0; i < MAX_ADAPTERS;  i++) {
-                                ctc_adapter[m][i].devno[WRITE] = -ENODEV;
-                                ctc_adapter[m][i].devno[READ] = -ENODEV;
-                        }
-                }
-                t = 1; 
-        }
+{				     
+	int	     m;
+	int	     i;
+	static int   t;
+
+	if (t == 0){
+		for (m = 0; m < CHANNEL_MEDIA;	m++) {
+			for (i = 0; i < MAX_ADAPTERS;  i++) {
+				ctc_adapter[m][i].devno[WRITE] = -ENODEV;
+				ctc_adapter[m][i].devno[READ] = -ENODEV;
+				ctc_adapter[m][i].netdev = NULL;
+			}
+		}
+		t = 1; 
+	}
 } 
 
 
 static int ctc_buffer_alloc(struct channel *ctc) {
-        
-        struct buffer    *p;
-        struct buffer    *q;
-
-        p = kmalloc(sizeof(p), GFP_KERNEL);
-        if (p == NULL) 
-                return -ENOMEM;
-        else {  
-                p->next = NULL;  
-                p->packets = 0;
-                p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
-                if (p->block == NULL) {
-                        kfree(p);
-                        return -ENOMEM;
-                }
-                p->block->length = 0; 
-        }
+	
+	struct buffer	 *p;
+	struct buffer	 *q;
+
+	p = kmalloc(sizeof(struct buffer), GFP_KERNEL);
+	if (p == NULL) 
+		return -ENOMEM;
+	else {	
+		p->next = NULL;	 
+		p->packets = 0;
+		p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
+		if (p->block == NULL) {
+			kfree(p);
+			return -ENOMEM;
+		}
+		p->block->length = 0; 
+	}
    
-        if (ctc->free_anchor == NULL) 
-                ctc->free_anchor = p;  
-        else {  
-                 q = ctc->free_anchor;
-                 while (q->next != NULL) 
-                        q = q->next;
-                 q->next = p;
-        }
-        ctc->buffer_count++;   
+	if (ctc->free_anchor == NULL) 
+		ctc->free_anchor = p;  
+	else {	
+		 q = ctc->free_anchor;
+		 while (q->next != NULL) 
+			q = q->next;
+		 q->next = p;
+	}
+	ctc->buffer_count++;   
    return 0;
 }
 
 
 static int ctc_buffer_free(struct channel *ctc) {
-        
-        struct buffer    *p;
+	
+	struct buffer	 *p;
 
-           
-        if (ctc->free_anchor == NULL)
-                return -ENOMEM;
-        
-        p = ctc->free_anchor; 
-        ctc->free_anchor = p->next;
-        free_pages((__u32)p->block, 4);
-        kfree(p);
-
-        return 0;
+	   
+	if (ctc->free_anchor == NULL)
+		return -ENOMEM;
+	
+	p = ctc->free_anchor; 
+	ctc->free_anchor = p->next;
+	free_pages((unsigned long)p->block, 4);
+	kfree(p);
+
+	return 0;
 }
 
 
-static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) {
-        
-        struct buffer    *p = NULL;
-        struct buffer    *q = NULL;
+static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to, net_device *dev) {
+	
+	struct buffer	 *p = NULL;
+	struct buffer	 *q = NULL;
  
-        if (*from == NULL)
-                return -ENOMEM; 
-
-        p = *from;
-        *from = p->next;
-        p->next = NULL;
-
-        if (*to == NULL)
-                *to = p;
-        else {
-                q = *to;
-                while (q->next != NULL)
-                        q = q->next;
-                q->next = p;
-
-        }
-        return 0;
-}
-
-
+	if (*from == NULL)
+	{
+		printk(KERN_DEBUG
+		       "%s: %s(): Trying to swap buffer from empty list - doing nothing\n", dev ? dev->name : "<unknown ctc dev>", __FUNCTION__); 
+		
+		return -ENOMEM; 
+	}
+
+	p = *from;
+	*from = p->next;
+	p->next = NULL;
+
+	if (*to == NULL)
+		*to = p;
+	else {
+		q = *to;
+		while (q->next != NULL)
+			q = q->next;
+		q->next = p;
+
+	}
+	return 0;
+}
+
+#ifdef MODULE
+   static void ctc_setup(char *dev_name,int *ints)
+#  define ctc_setup_return return
+#else
+#  if LINUX_VERSION_CODE>=0x020300
+     static int __init ctc_setup(char *dev_name)
+#    define ctc_setup_return return(1)
+#  else
+     __initfunc(void ctc_setup(char *dev_name,int *ints))
+#    define ctc_setup_return return
+#  endif
+#endif
 /*
  *   ctc_setup function 
  *     this function is called for each ctc= keyword passed into the kernel 
  *
  *     valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx 
- *     where n      is the channel protocol always 0 
- *           0xnnnn is the cu number  read 
- *           0xnnnn is the cu number  write 
- *           ctcx can be ctc0 to ctc7 or escon0 to escon7 
+ *     where n	    is the channel protocol always 0 
+ *	     0xnnnn is the cu number  read 
+ *	     0xnnnn is the cu number  write 
+ *	     ctcx can be ctc0 to ctc7 or escon0 to escon7 
  */
-#if LINUX_VERSION_CODE>=0x020300
-static int __init ctc_setup(char *dev_name)
-#else
-__initfunc(void ctc_setup(char *dev_name,int *ints))
-#endif
+
 {
-        struct adapterlist tmp;
+	struct adapterlist tmp;
+	int id;
 #if  LINUX_VERSION_CODE>=0x020300
 	#define CTC_MAX_PARMS 4
-	int ints[CTC_MAX_PARMS+1];	
-	get_options(dev_name,CTC_MAX_PARMS,ints);
-	#define ctc_setup_return return(1)
-#else
-	#define ctc_setup_return return
+	int ints[CTC_MAX_PARMS+1];  
+	dev_name = get_options(dev_name, CTC_MAX_PARMS, ints);
 #endif
-        ctc_tab_init();
-        
-        ctc_no_auto = 1;
-
-        if (!strcmp(dev_name,"noauto")) { 
-                printk(KERN_INFO "ctc: automatic channel selection deactivated\n");
-                ctc_setup_return;
-        }
-
-        tmp.devno[WRITE] = -ENODEV;
-        tmp.devno[READ] = -ENODEV; 
-
-        switch (ints[0]) {
-              
-                case 3: /* write channel passed */
-                        tmp.devno[WRITE] = ints[3]; 
-                        
-                case 2: /* read channel passed */
-                        tmp.devno[READ] = ints[2];
-                        if (tmp.devno[WRITE] == -ENODEV)
-                                tmp.devno[WRITE] = tmp.devno[READ] + 1; 
-
-                case 1: /* protocol type passed */
-                        tmp.protocol    = ints[1];
-                        if (tmp.protocol == 0) {
-                                break;    
-                        } else {
-                                printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
-                                ctc_setup_return;
-                        }
-                        break;
-
-                default: 
-                        printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
-                        ctc_setup_return;
-        }
-        ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp; 
-#ifdef DEBUG
-        printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n",
-             dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
-#endif  
-        ctc_setup_return;
-        
+	ctc_tab_init();
+
+	ctc_no_auto = 1;
+
+	if (!dev_name) { /* happens if device name is not specified in
+			    parameter line (cf. init/main.c:get_options() */
+		printk(KERN_WARNING
+		       "ctc: %s(): Device name not specified\n",
+		       __FUNCTION__); 
+		ctc_setup_return;
+	}
+		
+	if (!strcmp(dev_name,"noauto")) { 
+		printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); 
+		ctc_setup_return;
+	}
+
+	if ((id = extract_channel_id(dev_name)) == -EINVAL)
+	{
+		printk(KERN_WARNING
+		       "ctc: %s(): Invalid device name specified: %s\n",
+		       __FUNCTION__, dev_name); 
+		ctc_setup_return;
+	}
+
+	tmp.devno[WRITE] = -ENODEV;
+	tmp.devno[READ] = -ENODEV; 
+
+	switch (ints[0]) {
+	      
+		case 3: /* write channel passed */
+			tmp.devno[WRITE] = ints[3]; 
+			
+		case 2: /* read channel passed */
+			tmp.devno[READ] = ints[2];
+			if (tmp.devno[WRITE] == -ENODEV)
+				tmp.devno[WRITE] = tmp.devno[READ] + 1; 
+
+		case 1: /* protocol type passed */
+			tmp.protocol	= ints[1];
+			if (tmp.protocol == 0) {
+				break;	  
+			} else {
+				printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
+				ctc_setup_return;
+			}
+			break;
+
+		default: 
+			printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
+			ctc_setup_return;
+	}
+	ctc_adapter[extract_channel_media(dev_name)][id] = tmp; 
+#ifdef DEBUG
+	printk(KERN_DEBUG "%s: protocol=%x read=%04x write=%04x\n",
+	     dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
+#endif	
+	ctc_setup_return;
+	
 }
 #if LINUX_VERSION_CODE>=0x020300
 __setup("ctc=", ctc_setup);
@@ -763,102 +927,131 @@
 
 /*
  *   ctc_probe 
- *      this function is called for each channel network device, 
- *      which is defined in the /init/main.c 
+ *	this function is called for each channel network device, 
+ *	which is defined in the /init/main.c 
  */
 int ctc_probe(net_device *dev)
-{       
-        int                rc;
-        int                c;
-        int                i;
-        int                m;
-
-        struct ctc_priv    *privptr;
-
-        /* Only the first time the ctc_probe gets control */
-        if (channel_tab_initialized == 0) {  
-                channel_init();  
-
-
-        }
-        
-        ctc_tab_init();
-
-        m = extract_channel_media(dev->name);
-        i = extract_channel_id(dev->name);
-        
-        if (channel_left(m) <=1) 
-                return -ENODEV;
-
-        if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
-                return -ENODEV;
-
-        dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL);
-        if (dev->priv == NULL)
-                return -ENOMEM;
-        memset(dev->priv, 0, sizeof(struct ctc_priv));  
-        privptr = (struct ctc_priv *) (dev->priv);
-
-        
-        for (c = 0; c < 2; c++) {
-
-                privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
-                if (privptr->channel[c].devstat == NULL){
-                        if (i == WRITE)
-                                kfree(privptr->channel[READ].devstat);
-                        return -ENOMEM;  
-                }
-                memset(privptr->channel[c].devstat, 0, sizeof(devstat_t));
-
-                if (ctc_no_auto == 0) 
-                         ctc_adapter[m][i].devno[c] = channel_get_next(m);
-                else 
-                         ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
-
-                if ( ctc_adapter[m][i].devno[c] != -ENODEV){
-                         rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]),
-                              (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, 
-                              privptr->channel[c].devstat);
-                         if (rc) { 
-                                 printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
-                                 return -EBUSY;
-                         }
-                } else {        
-                        if (i == WRITE) {
-                                free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat);
-                                channel_free(m, ctc_adapter[m][i].devno[READ]);
-                                kfree(privptr->channel[READ].devstat);
-                        } 
-                        kfree(privptr->channel[i].devstat);
-                        return -ENODEV;
-                }
-        }
-
-        privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
-        privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
-        privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
-        privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
-        privptr->protocol = ctc_adapter[m][i].protocol;
-        channel[m].left = channel[m].left - 2;
-
-        printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
-            dev->name, privptr->channel[READ].devno,   privptr->channel[READ].irq,
-            privptr->channel[WRITE].devno,  privptr->channel[WRITE].irq); 
-
-        dev->mtu             = CTC_DEFAULT_MTU_SIZE;
-        dev->hard_start_xmit = ctc_tx;
-        dev->open            = ctc_open;
-        dev->stop            = ctc_release;
-        dev->get_stats       = ctc_stats;
-        dev->change_mtu      = ctc_change_mtu;
-        dev->hard_header_len = 0;
-        dev->addr_len        = 0;
-        dev->type            = ARPHRD_SLIP;
-        dev->tx_queue_len    = 100;
-        dev_init_buffers(dev);
-        dev->flags           = IFF_POINTOPOINT | IFF_NOARP;   
+{	
+	int		   rc;
+	int		   c;
+	int		   i;
+	int		   m;
+	struct ctc_priv	   *privptr;
+
+	/* Only the first time the ctc_probe gets control */
+	if (channel_tab_initialized == 0) {
+		channel_init();	 
+	}
+	
+	ctc_tab_init();
+
+	m = extract_channel_media(dev->name);
+	i = extract_channel_id(dev->name);
+	
+	if (channel_left(m) <= 1)
+		return -ENODEV;
+
+	if (i < 0 || i >= MAX_ADAPTERS)
+		return -ENODEV;
+
+	if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
+		return -ENODEV;
+
+	dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL|GFP_DMA);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0, sizeof(struct ctc_priv));
+	privptr = (struct ctc_priv *) (dev->priv);
+
+	
+	for (c = 0; c < 2; c++) {
+		devstat_t *devstat;
+		unsigned int devno;
+		
+		privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
+		devstat = privptr->channel[c].devstat;
+		if (devstat == NULL) {
+			if (c == 1) {
+				free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat);
+				channel_free(m, ctc_adapter[m][i].devno[0]);
+				kfree(privptr->channel[0].devstat);
+			}
+			kfree(dev->priv);
+			dev->priv = NULL;
+			return -ENOMEM;	 
+		}
+
+		memset(devstat, 0, sizeof(devstat_t));
+
+		if (ctc_no_auto == 0) {
+			ctc_adapter[m][i].devno[c] = channel_get_next(m);
+			devno = ctc_adapter[m][i].devno[c];
+		}
+		else {
+			ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
+			devno = ctc_adapter[m][i].devno[c];
+		}
+		
+
+		if (devno != -ENODEV) {
+			rc = request_irq(get_irq_by_devno(devno),
+					 ctc_irq_handler, SA_INTERRUPT, dev->name, 
+					 devstat);
+			if (rc) { 
+				printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
+				if (c == 1) {
+					free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]),
+						 privptr->channel[0].devstat);
+					channel_free(m, ctc_adapter[m][i].devno[0]);
+					kfree(privptr->channel[0].devstat);
+				}
+				channel_free(m, devno);
+				kfree(devstat);
+				kfree(dev->priv);
+				dev->priv = NULL;
+				return -EBUSY;
+			}
+		} else {	
+			if (c == 1) {
+				free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat);
+				channel_free(m, ctc_adapter[m][i].devno[0]);
+				kfree(privptr->channel[0].devstat);
+			} 
+			kfree(devstat);
+			kfree(dev->priv);
+			dev->priv = NULL;
+			return -ENODEV;
+		}
+	}
+
+	privptr->channel[READ].devno  = ctc_adapter[m][i].devno[READ];
+	privptr->channel[READ].irq    = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
+	privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
+	privptr->channel[WRITE].irq   = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
+	privptr->channel[READ].dev = privptr->channel[WRITE].dev = dev;
+	privptr->protocol = ctc_adapter[m][i].protocol;
+	channel[m].left = channel[m].left - 2;
+
+	print_banner();
+	printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
+	    dev->name, privptr->channel[READ].devno,   privptr->channel[READ].irq,
+	    privptr->channel[WRITE].devno,  privptr->channel[WRITE].irq); 
+
+	dev->mtu	         = CTC_DEFAULT_MTU_SIZE;
+	dev->hard_start_xmit     = ctc_tx;
+	dev->open	         = ctc_open;
+	dev->stop	         = ctc_release;
+	dev->get_stats	         = ctc_stats;
+	dev->change_mtu          = ctc_change_mtu;
+	dev->hard_header_len     = 6;
+	dev->addr_len            = 0;
+	dev->type                = ARPHRD_SLIP;
+	dev->tx_queue_len        = 100;
+	dev_init_buffers(dev);
+	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
+	ctc_adapter[m][i].netdev = dev;
 
-        return 0;
+	return 0;
 } 
 
 
@@ -867,456 +1060,563 @@
  *
  */
 
-static void inline ccw_check_return_code (net_device *dev, int return_code)
+static void inline ccw_check_return_code (net_device *dev, int return_code, char *caller)
 {
-        if (return_code != 0) {
-                switch (return_code) {
-                        case -EBUSY:  
-                                printk(KERN_INFO "%s: Busy !\n", dev->name);
-                                break;
-                        case -ENODEV:
-                                printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name);
-                                break;
-                        case -EIO:
-                                printk(KERN_EMERG "%s: Status pending... \n", dev->name);
-                                break;
-                        default:
-                                printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", 
-                                    dev->name, return_code);
-                }
-        }
+	if (return_code != 0) {
+		switch (return_code) {
+			case -EBUSY:  
+				printk(KERN_INFO "%s: %s: Busy !\n", dev->name, caller);
+				break;
+			case -ENODEV:
+				printk(KERN_EMERG "%s: %s: Invalid device called for IO\n", dev->name, caller);
+				break;
+			case -EIO:
+				printk(KERN_EMERG "%s: %s: Status pending... \n", dev->name, caller);
+				break;
+			default:
+				printk(KERN_EMERG "%s: %s: Unknown error in Do_IO %04x\n", 
+				    dev->name, caller, return_code);
+		}
+	}
 } 
 
 
-static void inline ccw_check_unit_check (net_device *dev, char sense)
+static void inline ccw_check_unit_check (net_device *dev, char sense, char *caller)
 {
 #ifdef DEBUG
-        printk(KERN_INFO "%s: Unit Check with sense code: %02x\n",
-            dev->name, sense);
+	printk(KERN_INFO "%s: %s: Unit Check with sense code: %02x\n",
+	    dev->name, caller, sense);
 #endif
 
-        if (sense & 0x40) {
+	if (sense & 0x40) {
 #ifdef DEBUG
-                if (sense & 0x01) 
-                        printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name);
-                else 
-                        printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name);
-#endif
-        } else if (sense & 0x20) {
-                if (sense & 0x04)
-                        printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name);
-                else 
-                        printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name);
-        } else if (sense & 0x10) {
-                if (sense & 0x20)
-                        printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name);
-                else 
-                        printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name);
-        }
+		if (sense & 0x01) 
+			printk(KERN_DEBUG "%s: %s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name, caller);
+		else 
+			printk(KERN_DEBUG "%s: %s: System reset occured (remote side)\n", dev->name, caller);
+#endif
+	} else if (sense & 0x20) {
+		if (sense & 0x04)
+			printk(KERN_WARNING "%s: %s: Data-streaming timeout)\n", dev->name, caller);
+		else 
+			printk(KERN_WARNING "%s: %s: Data-transfer parity error\n", dev->name, caller);
+	} else if (sense & 0x10) {
+		if (sense & 0x20)
+			printk(KERN_WARNING "%s: %s: Hardware malfunction (remote side)\n", dev->name, caller);
+		else 
+			printk(KERN_WARNING "%s: %s: Read-data parity error (remote side)\n", dev->name, caller);
+	}
 
 } 
 
-
+ 
 static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
 {
-        int               rc = 0;
-        __u32             parm;
-        __u8              flags = 0x00;
-        struct  channel   *ctc = NULL;
-        struct  ctc_priv  *privptr = NULL;
-        net_device        *dev = NULL;    
-        
-       /* ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
-                                               {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}};    */
-                                               
-       ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL},
-                                               {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; 
+	int		  rc = 0;
+	__u32		  parm;
+	__u8		  flags = 0x00;
+	struct	channel	  *ctc = NULL;
+	struct	ctc_priv  *privptr = NULL;
+	net_device	  *dev = NULL;	  
+	
+       /* ccw1_t	    ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+					       {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}};	  */
+					       
+	static ccw1_t	 ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, 0},
+					       {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, 0}};
 
 
 
-        devstat_t *devstat = ((devstat_t *)initparm);
+	devstat_t *devstat = ((devstat_t *)initparm);
 
-        /* Bypass all 'unsolicited interrupts' */
-        if (devstat->intparm == 0) {
+	/* Bypass all 'unsolicited interrupts' */
+	if (devstat->intparm == 0) {
 #ifdef DEBUG
-                printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
-                    devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
+		printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received cstat: %02x dstat: %02x flag: %02x\n",
+		    devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
 #endif 
-                /* FIXME - find the related intparm!!! No IO outstanding!!!! */
-                return;
-        }
-
-        ctc = (struct channel *) (devstat->intparm);
-        dev = (net_device *) ctc->dev;
-        privptr = dev->priv;
+		/* FIXME - find the related intparm!!! No IO outstanding!!!! */
+		return;
+	}
+
+	ctc = (struct channel *) (devstat->intparm);
+	if(ctc==NULL) 
+	{
+		printk(KERN_CRIT "ctc:ctc_irq_handler ctc=NULL irq=%d\n",irq);
+		return;
+	}
+	
+	dev = (net_device *) ctc->dev;
+	if(dev==NULL) 
+	{
+		printk(KERN_CRIT "ctc:ctc_irq_handler dev=NULL irq=%d, ctc=0x%p\n",
+					 irq, ctc);
+		return;
+	}
+
+	privptr = dev->priv;
+	if(privptr==NULL)
+	{
+		printk(KERN_CRIT "ctc:ctc_irq_handler privptr=NULL "
+					 "irq=%d, ctc=0x%p, dev=0x%p\n", irq, ctc, privptr);
+		return;
+	}
 
 #ifdef DEBUG
-        printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
-            dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
+	printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
+	    dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
 #endif 
 
-        /* Check for good subchannel return code, otherwise error message */
-        if (devstat->cstat) {
-                printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", 
-                    dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
-                return;
-        }
+	/* Check for good subchannel return code, otherwise error message */
+	if (devstat->cstat) {
+		printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", 
+		    dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
+		return;
+	}
 
 
-        /* Check the reason-code of a unit check */
-        if (devstat->dstat & DEV_STAT_UNIT_CHECK)
-                ccw_check_unit_check(dev, devstat->ii.sense.data[0]);
+	/* Check the reason-code of a unit check */
+	if (devstat->dstat & DEV_STAT_UNIT_CHECK)
+		ccw_check_unit_check(dev, devstat->ii.sense.data[0], __FUNCTION__ "()");
 
 
-        /* State machine to bring the connection up / down and to restart */ 
+	/* State machine to bring the connection up / down and to restart */ 
 
-        ctc->last_dstat = devstat->dstat;
+	ctc->last_dstat = devstat->dstat;
 
-        switch (ctc->state) {   
+	switch (ctc->state) {	
 
-                case CTC_STOP:           /* HALT_IO issued by ctc_release (halt sequence) */
-                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return;
-                        wake_up(&ctc->wait);   /* wake up ctc_release */
-                        return;
+		case CTC_STOP:		 /* HALT_IO issued by ctc_release (halt sequence) */
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_STOP");
+#endif 
+			if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+				return;
+			ctc->flag |= CTC_WAKEUP;
+			wake_up(&ctc->wait);   /* wake up ctc_release */
+			return;
  
 
-                case CTC_START_HALT_IO:  /* HALT_IO issued by ctc_open (start sequence) */
-                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return;
-
-                        ctc->state = CTC_START_SET_X_MODE;
-                        parm = (__u32) ctc;
-                        rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
-                        if (rc != 0)
-                                ccw_check_return_code(dev, rc);
-                        return;
+		case CTC_START_HALT_IO:	 /* HALT_IO issued by ctc_open (start sequence) */
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_HALT_IO");
+#endif 
+			if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+				return;
+
+			ctc->state = CTC_START_SET_X_MODE;
+			parm = (__u32)(long) ctc;
+			rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
+			if (rc != 0)
+				ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+			return;
  
-        
-                case CTC_START_SET_X_MODE:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) != 0x40) {
-                                        wake_up(&ctc->wait);  /* wake up ctc_open (READ or WRITE) */
-                                        return; 
-                                }        
-                        }
-                        if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return;
-                        ctc->state =  CTC_START_SELECT;
+	
+		case CTC_START_SET_X_MODE:
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_SET_X_MODE");
+#endif 
+			if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+				if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
+				    (devstat->ii.sense.data[0] & 0x40) != 0x40) {
+					ctc->flag |= CTC_WAKEUP;
+					wake_up(&ctc->wait);  /* wake up ctc_open (READ or WRITE) */
+					return; 
+				}	 
+			}
+			if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+				return;
+			ctc->state =  CTC_START_SELECT;
  
 
-                case CTC_START_SELECT:
-                        if (!ctc->flag & CTC_WRITE) {
-                                ctc->state = CTC_START_READ_TEST;
-                                ctc->free_anchor->block->length = 0;    
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                                parm = (__u32) ctc;
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                if (rc != 0) 
-                                        ccw_check_return_code(dev, rc);
-                                wake_up(&ctc->wait);  /* wake up ctc_open (READ) */
-
-                        } else {
-                                ctc->state = CTC_START_WRITE_TEST;
-                                /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
-                                ctc->free_anchor->block->length = 0;    
-                                ctc->ccw[1].count = 2;              /* Transfer only length */
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                                parm = (__u32) ctc; 
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
-                                if (rc != 0)
-                                        ccw_check_return_code(dev, rc);
-                        }
-                        return;
-
-
-                case CTC_START_READ_TEST:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
-                                    devstat->ii.sense.data[0] == 0                ) {
-                                        init_timer(&ctc->timer);
-                                        ctc->timer.function = (void *)ctc_read_retry; 
-                                        ctc->timer.data = (__u32)ctc;
-                                        ctc->timer.expires = jiffies + 10*HZ;
-                                        add_timer(&ctc->timer);
+		case CTC_START_SELECT:
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_SELECT");
+#endif 
+			if(ctc->free_anchor==NULL)
+			{
+				printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_SELECT ctc_free_anchor=NULL "
+							 "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
+				return;
+			}
+			if (!(ctc->flag & CTC_WRITE)) {
+				ctc->state = CTC_START_READ_TEST;
+				ctc->free_anchor->block->length = 0;	
+				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
+				parm = (__u32)(long) ctc;
+				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+				if (rc != 0) 
+					ccw_check_return_code(dev, rc, __FUNCTION__ "()[2]");
+				ctc->flag |= CTC_WAKEUP;
+				wake_up(&ctc->wait);  /* wake up ctc_open (READ) */
+
+			} else {
+				ctc->state = CTC_START_WRITE_TEST;
+				/* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
+				ctc->free_anchor->block->length = 0;	
+				ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */
+				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
+				parm = (__u32)(long) ctc; 
+				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+				if (rc != 0)
+					ccw_check_return_code(dev, rc, __FUNCTION__ "()[3]");
+			}
+			return;
+
+
+		case CTC_START_READ_TEST:
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_READ_TEST");
+#endif 
+			if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+				if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+				    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+				    devstat->ii.sense.data[0] == 0		  ) {
+					init_timer(&ctc->timer);
+					ctc->timer.function = ctc_read_retry;
+					ctc->timer.data = (unsigned long)ctc;
+					ctc->timer.expires = jiffies + 10*HZ;
+					add_timer(&ctc->timer);
 #ifdef DEBUG 
-                                        printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); 
+					printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); 
 #endif
-                                }
-                                return;
-                        }
-
-                        if ((devstat->dstat &  ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
-                                if ((devstat->dstat & DEV_STAT_ATTENTION) && 
-                                    (devstat->dstat & DEV_STAT_BUSY)) {
-                                        printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
-                                } 
-                                wake_up(&privptr->channel[WRITE].wait);  /* wake up ctc_open (WRITE) */
-                                return;
-                        }
-
-                        ctc->state = CTC_START_READ;
-                        set_bit(0, (void *)&ctc->IO_active);
-
-                        /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
-                        /* wake_up(&privptr->channel[WRITE].wait);*/  /* wake up ctc_open (WRITE) */
-
-
-                case CTC_START_READ: 
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
-                                    devstat->ii.sense.data[0] == 0               ) {
-                                        privptr->stats.rx_errors++;
+				}
+				return;
+			}
+
+			if ((devstat->dstat &  ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+				if ((devstat->dstat & DEV_STAT_ATTENTION) && 
+				    (devstat->dstat & DEV_STAT_BUSY)) {
+					printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
+				} 
+				privptr->channel[WRITE].flag |= CTC_WAKEUP;
+				wake_up(&privptr->channel[WRITE].wait);	 /* wake up ctc_open (WRITE) */
+				return;
+			}
+
+			ctc->state = CTC_START_READ;
+			set_bit(0, &ctc->IO_active);
+
+			/* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
+			/* wake_up(&privptr->channel[WRITE].wait);*/  /* wake up ctc_open (WRITE) */
+
+
+		case CTC_START_READ:
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_READ");
+#endif 
+			if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+				if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+				    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+				    devstat->ii.sense.data[0] == 0		 ) {
+					privptr->stats.rx_errors++;
 					/* Need protection here cos we are in the read irq */
 					/*  handler the tbusy is for the write subchannel */
 					ctc_protect_busy(dev);
-				        ctc_setbit_busy(TB_RETRY,dev);
+					ctc_setbit_busy(TB_RETRY,dev);
 					ctc_unprotect_busy(dev);
-                                        init_timer(&ctc->timer);
-                                        ctc->timer.function = (void *)ctc_read_retry; 
-                                        ctc->timer.data = (__u32)ctc;
-                                        ctc->timer.expires = jiffies + 30*HZ;
-                                        add_timer(&ctc->timer); 
-                                        printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
-                                }
-                                return;
-                        }
+					init_timer(&ctc->timer);
+					ctc->timer.function = ctc_read_retry; 
+					ctc->timer.data = (unsigned long)ctc;
+					ctc->timer.expires = jiffies + 30*HZ;
+					add_timer(&ctc->timer); 
+					printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
+				}
+				return;
+			}
 
-                        if(!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                return; 
+			if(!(devstat->flag & DEVSTAT_FINAL_STATUS))
+				return; 
 			ctc_protect_busy(dev);
 			ctc_clearbit_busy(TB_RETRY,dev);
 			ctc_unprotect_busy(dev);
-                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
+			ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
+
+			if (ctc->free_anchor != NULL) {
+				ctc->free_anchor->block->length = 0;
+				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
+				parm = (__u32)(long) ctc;
+				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+				if (rc != 0) 
+					ccw_check_return_code(dev, rc, __FUNCTION__ "()[4]");
+			} else {
+				clear_bit(0, &ctc->IO_active);	  
+#ifdef DEBUG
+				printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
+#endif
+			}
+			
+			if (test_and_set_bit(CTC_BH_ACTIVE, &ctc->flag_a) == 0) {
+				queue_task(&ctc->tq, &tq_immediate);
+				mark_bh(IMMEDIATE_BH);
+			}
+			return;
 
-                        if (ctc->free_anchor != NULL) {  
-                                ctc->free_anchor->block->length = 0;
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                                parm = (__u32) ctc;
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                if (rc != 0) 
-                                        ccw_check_return_code(dev, rc);
-                        } else {
-                                clear_bit(0, (void *)&ctc->IO_active);    
-#ifdef DEBUG
-                                printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
-#endif
-                        }
-                        
-                        if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) {
-                                queue_task(&ctc->tq, &tq_immediate);
-                                mark_bh(IMMEDIATE_BH);
-                        }
-                        return;
-
-
-                case CTC_START_WRITE_TEST:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
-                                    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
-                                    devstat->ii.sense.data[0] == 0                ) {
-                                        init_timer(&ctc->timer);
-                                        ctc->timer.function = (void *)ctc_write_retry; 
-                                        ctc->timer.data = (__u32)ctc;
-                                        ctc->timer.expires = jiffies + 10*HZ;
-                                        add_timer(&ctc->timer);
-#ifdef DEBUG
-                                        printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
-#endif
-                                }
-                                return;
-                        }
-
-                        ctc->state = CTC_START_WRITE;
-                        wake_up(&ctc->wait);  /* wake up ctc_open (WRITE) */
-                        return;
+
+		case CTC_START_WRITE_TEST:
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_WRITE_TEST");
+#endif 
+			if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+				if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+				    (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+				    devstat->ii.sense.data[0] == 0		  ) {
+					init_timer(&ctc->timer);
+					ctc->timer.function = ctc_write_retry; 
+					ctc->timer.data = (unsigned long)ctc;
+					ctc->timer.expires = jiffies + 10*HZ;
+					add_timer(&ctc->timer);
+#ifdef DEBUG
+					printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
+#endif
+				}
+				return;
+			}
+
+			ctc->state = CTC_START_WRITE;
+			ctc->flag |= CTC_WAKEUP;
+			wake_up(&ctc->wait);  /* wake up ctc_open (WRITE) */
+			return;
  
 
-                case CTC_START_WRITE:
-                        if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
-                                privptr->stats.tx_errors += ctc->proc_anchor->packets;
-#ifdef DEBUG
-                                printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
-#endif
-                        } else { 
-                                if (!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                        return; 
-                                privptr->stats.tx_packets += ctc->proc_anchor->packets;
-                        } 
-
-                        ctc->proc_anchor->block->length = 0;
-                        ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-                        ctc_clearbit_busy(TB_NOBUFFER,dev);      
-                        if (ctc->proc_anchor != NULL) {  
-#ifdef DEBUG
-                                printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); 
-#endif
-                                ctc->ccw[1].count = ctc->proc_anchor->block->length;
-                                ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
-                                parm = (__u32) ctc;
-                                rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                if (rc != 0) 
-                                        ccw_check_return_code(dev, rc);
-                                dev->trans_start = jiffies;
-                                return;
-
-                        }
-
-                        if (ctc->free_anchor->block->length != 0) {
-                                if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {     
-                                       /* set transmission to busy */
-                                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-                                        ctc_clearbit_busy(TB_TX,dev);
-#ifdef DEBUG
-                                        printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); 
-#endif
-                                        ctc->ccw[1].count = ctc->proc_anchor->block->length;
-                                        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
-                                        parm = (__u32) ctc;
-                                        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                                        if (rc != 0) 
-                                                ccw_check_return_code(dev, rc);
-                                        dev->trans_start = jiffies;
-                                        return;
-                                }
-                        } 
+		case CTC_START_WRITE:
+#ifdef DEBUG
+		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_WRITE");
+#endif 
+			if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+				privptr->stats.tx_errors += ctc->proc_anchor->packets;
+#ifdef DEBUG
+				printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
+#endif
+			} else { 
+				if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+					return; 
+				privptr->stats.tx_packets += ctc->proc_anchor->packets;
+			} 
+
+			ctc->proc_anchor->block->length = 0;
+			ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
+			ctc_clearbit_busy(TB_NOBUFFER, dev);	 
+			if (ctc->proc_anchor != NULL) {	 
+#ifdef DEBUG
+				printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); 
+#endif
+				ctc->ccw[1].count = ctc->proc_anchor->block->length;
+				ctc->ccw[1].cda	 = __pa(ctc->proc_anchor->block);
+				parm = (__u32)(long) ctc;
+				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+				if (rc != 0) 
+					ccw_check_return_code(dev, rc, __FUNCTION__ "()[5]");
+				dev->trans_start = jiffies;
+				return;
+
+			}
+			if (ctc->free_anchor==NULL) {
+				printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_WRITE ctc_free_anchor=NULL "
+							 "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
+				return;
+			}
+			if (ctc->free_anchor->block->length != 0) {
+				if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {	    
+				       /* set transmission to busy */
+					ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
+					ctc_clearbit_busy(TB_TX,dev);
+#ifdef DEBUG
+					printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); 
+#endif
+					ctc->ccw[1].count = ctc->proc_anchor->block->length;
+					ctc->ccw[1].cda	 = __pa(ctc->proc_anchor->block);
+					parm = (__u32)(long) ctc;
+					rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+					if (rc != 0) 
+						ccw_check_return_code(dev, rc, __FUNCTION__ "()[6]");
+					dev->trans_start = jiffies;
+					return;
+				}
+			} 
 
-                        clear_bit(0, (void *)&ctc->IO_active);              /* set by ctc_tx or ctc_bh */
-                        return;
+			clear_bit(0, &ctc->IO_active);		    /* set by ctc_tx or ctc_bh */
+			return;
 
  
-                default: 
-                        printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
-                        return;  
-        }
+		default: 
+			printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
+			return;	 
+	}
 } 
 
 
-static void ctc_irq_bh (struct channel *ctc)
+static void ctc_irq_bh (void *data)
 {
-        int                rc = 0;
-        __u16              data_len;
-        __u32              parm;
-
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        net_device  *dev;
-        struct ctc_priv    *privptr;             
-        struct packet      *lp;
-        struct sk_buff     *skb;
+	struct channel    *ctc = (struct channel *) data;
+	net_device        *dev = (net_device *) ctc->dev; 
+	struct ctc_priv	  *privptr = (struct ctc_priv *) dev->priv; 
+
+	int		   rc = 0;
+	__u16		   data_len;
+	__u32		   parm;
+
+	__u8		   flags = 0x00;
+	unsigned long	   saveflags;
+	struct block       *block;
+	struct packet	   *lp;
+	struct sk_buff	   *skb;
 
-        dev = (net_device *) ctc->dev; 
-        privptr = (struct ctc_priv *) dev->priv; 
    
 #ifdef DEBUG
-        printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
+	printk(KERN_DEBUG "%s: %s(): initial_block_received = %d\n" ,dev->name, __FUNCTION__, ctc->initial_block_received);
+	printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
 #endif 
 
-        while (ctc->proc_anchor != NULL) { 
-
-                if (ctc->proc_anchor->block->length != 0) {
-
-                        lp = &ctc->proc_anchor->block->data;
-                while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
-                        data_len = lp->length - PACKET_HEADER_LENGTH;
-                        skb = dev_alloc_skb(data_len); 
-                        if (skb) { 
-                                memcpy(skb_put(skb, data_len),&lp->data, data_len);
-                                skb->mac.raw = skb->data;
-                                skb->dev = dev;
-                                skb->protocol = htons(ETH_P_IP);
-                                skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
-                                netif_rx(skb);
-                                privptr->stats.rx_packets++;
-                        } else {
-                                privptr->stats.rx_dropped++; 
-                                        printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
-                        }
-                        (__u8 *)lp += lp->length;
-                }
-                }
+	while (ctc->proc_anchor != NULL) {
+		block = ctc->proc_anchor->block;
+		if (block->length < BLOCK_HEADER_LENGTH) {
+			if(block->length == 0 && !ctc->initial_block_received)
+				ctc->initial_block_received = 1;
+			else
+				printk(KERN_INFO "%s: %s(): discarding block at 0x%p: "
+				       "block length=%d<%d=block header length\n",
+				       dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH);
+		}
+		else {
+			lp = &block->data;
+			while ((__u8 *) lp < (__u8 *) block + block->length) {
+				if(lp->length < PACKET_HEADER_LENGTH) {
+					printk(KERN_INFO "%s: %s(): discarding rest of block at 0x%p (block length=%d:) "
+					       "packet at 0x%p, packet length=%d<%d=packet header length\n",
+					       dev->name, __FUNCTION__,
+					       block, block->length, lp, lp->length, PACKET_HEADER_LENGTH);
+					break;
+				}
+				
+				data_len = lp->length - PACKET_HEADER_LENGTH;
+#ifdef DEBUG
+				printk(KERN_DEBUG "%s: %s(): block=0x%p, block->length=%d, lp=0x%p, "
+				       "lp->length=%d, data_len=%d\n",
+				       dev->name, __FUNCTION__, block, block->length, lp, lp->length, data_len);
+#endif
+				skb = dev_alloc_skb(data_len); 
+				if (skb) { 
+					memcpy(skb_put(skb, data_len),&lp->data, data_len);
+					skb->mac.raw = skb->data;
+					skb->dev = dev;
+					skb->protocol = htons(ETH_P_IP);
+					skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
+					netif_rx(skb);
+					privptr->stats.rx_packets++;
+				} else {
+					privptr->stats.rx_dropped++; 
+					printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
+				}
+				(__u8 *)lp += lp->length; 
+			}
+		}
 
-                s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
+		s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+		ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
 
-                if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) {
+		if (test_and_set_bit(0, &ctc->IO_active) == 0) {
+#ifdef DEBUG
+			printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+#endif 
+			if(ctc->free_anchor==NULL || ctc->free_anchor->block==NULL)
+			{
+				printk(KERN_CRIT "ctc: bad anchor free_anchor "
+							 "ctc=0x%p, ctc->free_anchor=0x%p, ctc->irq=%d\n",
+							 ctc, ctc->free_anchor, ctc->irq);
+			}
+			else
+			{
+				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
+				parm = (__u32)(long) ctc; 
+				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+				if (rc != 0) 
+					ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+			}
+		} 
+		s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); 
+	}
+	clear_bit(CTC_BH_ACTIVE, &ctc->flag_a);
 #ifdef DEBUG
-                        printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+	printk(KERN_DEBUG "%s: end bh routine - state-%02x\n" ,dev->name, ctc->state);
 #endif 
-                        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-                        parm = (__u32) ctc; 
-                        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-                        if (rc != 0) 
-                                 ccw_check_return_code(dev, rc);
-                } 
-                s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); 
-        }
-        clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a);
-        return;
+	return;
 }  
 
 
-static void ctc_read_retry (struct channel *ctc)
+static void ctc_read_retry (unsigned long data)
 {
-        int                rc = 0;
-        __u32              parm;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        net_device  *dev;
+	struct channel    *ctc = (struct channel *) data;
+	net_device        *dev = (net_device *) ctc->dev; 
+	int		   rc = 0;
+	__u32		   parm;
+	__u8		   flags = 0x00;
+	unsigned long	   saveflags;
+ 
 
-        dev = (net_device *) ctc->dev; 
-   
 #ifdef DEBUG
-        printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
-#endif 
-        if (ctc->state == CTC_STOP)
-                return;
-        s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-        ctc->free_anchor->block->length = 0;
-        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
-        parm = (__u32) ctc; 
-        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-        s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
-        if (rc != 0) 
-                ccw_check_return_code(dev, rc);
-        return;
+	printk(KERN_DEBUG "%s: read retry - state-%02x\n",
+	       dev->name, ctc->state);
+#endif	
+	s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+	if (ctc->state != CTC_STOP) {
+		if (!ctc->free_anchor) {
+			s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+			printk(KERN_WARNING
+			       "%s: %s(): ctc->free_anchor=NULL, ctc=0x%p\n",
+			       dev->name, __FUNCTION__, ctc);
+			return;
+		}
+
+		ctc->free_anchor->block->length = 0;
+		ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
+		parm = (__u32)(long) ctc; 
+		rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+	}
+
+	s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+
+	if (rc != 0) 
+		ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+	return;
 }  
  
 
-static void ctc_write_retry (struct channel *ctc)
+static void ctc_write_retry (unsigned long data)
 {
-        int                rc = 0;
-        __u32              parm;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        net_device  *dev;
+	struct channel    *ctc = (struct channel *) data;
+	net_device        *dev = (net_device *) ctc->dev; 
+	int		   rc = 0;
+	__u32		   parm;
+	__u8		   flags = 0x00;
+	unsigned long	   saveflags;
 
-        dev = (net_device *) ctc->dev; 
    
 #ifdef DEBUG
-        printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
-#endif 
-        if (ctc->state == CTC_STOP)
-                return;
- 
-        while (ctc->proc_anchor != NULL) { 
-                ctc->proc_anchor->block->length = 0;
-                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-        } 
-
-        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-        s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-        ctc->ccw[1].count = 2;
-        ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
-        parm = (__u32) ctc; 
-        rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
-        s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
-        if (rc != 0) 
-                ccw_check_return_code(dev, rc);
-        return;
+	printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
+#endif	
+
+	if (ctc->proc_anchor != NULL) { 
+		printk(KERN_WARNING "%s: %s(): ctc->proc_anchor != NULL\n" ,dev->name, __FUNCTION__);
+	}
+
+	s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+
+	if (ctc->state != CTC_STOP)
+	{
+		ctc->ccw[1].count = 2;
+		ctc->ccw[1].cda	 = __pa(ctc->proc_anchor->block);
+		parm = (__u32)(long) ctc; 
+		rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+	}
+	
+	s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+
+	if (rc != 0) 
+		ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+	return;
 }  
 
 
@@ -1327,123 +1627,139 @@
  */
 static int ctc_open(net_device *dev)
 {
-        int                rc;
-        int                i;
-        int                j;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        __u32              parm;
-        struct ctc_priv    *privptr;
-	DECLARE_WAITQUEUE(wait, current);
-        struct timer_list  timer;
-
-
-        ctc_set_busy(dev);
-
-        privptr = (struct ctc_priv *) (dev->priv);
-        
-        privptr->channel[READ].flag  = 0x00;
-        privptr->channel[WRITE].flag = CTC_WRITE;
-
-        for (i = 0; i < 2;  i++) { 
-                for (j = 0; j < CTC_BLOCKS;  j++) { 
-                        rc = ctc_buffer_alloc(&privptr->channel[i]);
-                        if (rc != 0)
-                                return -ENOMEM;
-                }
-                init_waitqueue_head(&privptr->channel[i].wait);
-                privptr->channel[i].tq.next = NULL;
-                privptr->channel[i].tq.sync = 0;
-                privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh;
-                privptr->channel[i].tq.data = &privptr->channel[i]; 
-
-                privptr->channel[i].dev = dev;
-                
-                privptr->channel[i].flag_a = 0;
-                privptr->channel[i].IO_active = 0;
-
-                privptr->channel[i].ccw[0].cmd_code  = CCW_CMD_PREPARE;
-                privptr->channel[i].ccw[0].flags     = CCW_FLAG_SLI | CCW_FLAG_CC;
-                privptr->channel[i].ccw[0].count     = 0;
-                privptr->channel[i].ccw[0].cda       = NULL;
-                if (i == READ) {  
-                        privptr->channel[i].ccw[1].cmd_code  = CCW_CMD_READ;
-                        privptr->channel[i].ccw[1].flags     = CCW_FLAG_SLI;
-                        privptr->channel[i].ccw[1].count     = 0xffff;   /* MAX size */
-                        privptr->channel[i].ccw[1].cda       = NULL;
-                } else {
-                        privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
-                        privptr->channel[i].ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-                        privptr->channel[i].ccw[1].count    = 0;
-                        privptr->channel[i].ccw[1].cda      = NULL;
-                }
-                privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP;      /* jointed CE+DE */
-                privptr->channel[i].ccw[2].flags    = CCW_FLAG_SLI;
-                privptr->channel[i].ccw[2].count    = 0;
-                privptr->channel[i].ccw[2].cda      = NULL;
-                
-                privptr->channel[i].flag  &= ~CTC_TIMER;
-                init_timer(&timer);
-                timer.function = (void *)ctc_timer; 
-                timer.data = (__u32)&privptr->channel[i];
-                timer.expires = jiffies + 300*HZ;                        /* time to connect with the remote side */
-                add_timer(&timer);
-
-                s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
-                parm = (unsigned long) &privptr->channel[i]; 
-                privptr->channel[i].state = CTC_START_HALT_IO;
-                rc = halt_IO(privptr->channel[i].irq, parm, flags);
-                add_wait_queue(&privptr->channel[i].wait, &wait);
-                current->state = TASK_INTERRUPTIBLE;
-                s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
-                schedule();
-                remove_wait_queue(&privptr->channel[i].wait, &wait);
-                if(rc != 0)
-                        ccw_check_return_code(dev, rc);
-                if((privptr->channel[i].flag & CTC_TIMER) == 0x00)
-                        del_timer(&timer);
-        }
-
-        if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & 
-               ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
-            (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
+	int		   rc, wait_rc;
+	int		   i, ii;
+	int		   j;
+	__u8		   flags = 0x00;
+	unsigned long	   saveflags;
+	__u32		   parm;
+	struct ctc_priv	   *privptr;
+	struct timer_list  timer;
+
+
+	ctc_set_busy(dev);
+
+	privptr = (struct ctc_priv *) (dev->priv);
+	
+	privptr->channel[READ].flag  = 0x00;
+	privptr->channel[WRITE].flag = CTC_WRITE;
+
+	for (i = 0; i < 2;  i++) { 
+		privptr->channel[i].free_anchor = NULL;
+		privptr->channel[i].proc_anchor = NULL;;
+		for (j = 0; j < CTC_BLOCKS;  j++) { 
+			rc = ctc_buffer_alloc(&privptr->channel[i]);
+			if (rc != 0)
+				return -ENOMEM;
+		}
+		init_waitqueue_head(&privptr->channel[i].wait);
+		privptr->channel[i].tq.next = NULL;
+		privptr->channel[i].tq.sync = 0;
+		privptr->channel[i].tq.routine = ctc_irq_bh;
+		privptr->channel[i].tq.data = &privptr->channel[i]; 
+
+		privptr->channel[i].initial_block_received = 0;
+
+		privptr->channel[i].dev = dev;
+		
+		privptr->channel[i].flag_a = 0;
+		privptr->channel[i].IO_active = 0;
+
+		privptr->channel[i].ccw[0].cmd_code  = CCW_CMD_PREPARE;
+		privptr->channel[i].ccw[0].flags     = CCW_FLAG_SLI | CCW_FLAG_CC;
+		privptr->channel[i].ccw[0].count     = 0;
+		privptr->channel[i].ccw[0].cda	     = 0;
+		if (i == READ) {  
+			privptr->channel[i].ccw[1].cmd_code  = CCW_CMD_READ;
+			privptr->channel[i].ccw[1].flags     = CCW_FLAG_SLI;
+			privptr->channel[i].ccw[1].count     = 0xffff;   /* MAX size */
+			privptr->channel[i].ccw[1].cda	     = 0;
+		} else {
+			privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
+			privptr->channel[i].ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
+			privptr->channel[i].ccw[1].count    = 0;
+			privptr->channel[i].ccw[1].cda	    = 0;
+		}
+		privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP;	 /* jointed CE+DE */
+		privptr->channel[i].ccw[2].flags    = CCW_FLAG_SLI;
+		privptr->channel[i].ccw[2].count    = 0;
+		privptr->channel[i].ccw[2].cda	    = 0;
+		
+		privptr->channel[i].flag  &= ~(CTC_TIMER | CTC_WAKEUP);
+		init_timer(&timer);
+		timer.function = ctc_timer; 
+		timer.data = (unsigned long)&privptr->channel[i];
+		timer.expires = jiffies + 300*HZ;			 /* time to connect with the remote side */
+		add_timer(&timer);
+
+		s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+		parm = (unsigned long) &privptr->channel[i]; 
+		privptr->channel[i].state = CTC_START_HALT_IO;
+		rc = halt_IO(privptr->channel[i].irq, parm, flags);
+		s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+
+		wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+		del_timer(&timer);
+
+		if(rc != 0)
+			ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+		if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */
+			for (ii=0; ii<=i; ii++) {
+
+				del_timer(&privptr->channel[ii].timer);
+
+				for (j=0; privptr->channel[ii].free_anchor != NULL && j < CTC_BLOCKS;  j++)
+					ctc_buffer_free(&privptr->channel[ii]);
+
+				if (privptr->channel[ii].free_anchor != NULL)
+					printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+								 dev->name, __FUNCTION__, CTC_BLOCKS);
+			}
+			return -ERESTARTSYS;
+		}
+	}
+	
+	if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & 
+	       ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+	    (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
 #ifdef DEBUG
-                printk(KERN_DEBUG "%s: channel problems during open - read: %02x -  write: %02x\n",
-                    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+		printk(KERN_DEBUG "%s: channel problems during open - read: %02x -  write: %02x\n",
+		    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
 #endif 
-                printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
-                
-                for (i = 0; i < 2;  i++) {
-                     /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
-                        parm = (unsigned long) &privptr->channel[i];
-                        privptr->channel[i].state = CTC_STOP;
-                        rc = halt_IO(privptr->channel[i].irq, parm, flags); /
-                        s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
-                        if (rc != 0)
-                                ccw_check_return_code(dev, rc);     */
-                        for (j = 0; j < CTC_BLOCKS;  j++) 
-                                ctc_buffer_free(&privptr->channel[i]);
-                }
-                return -EIO;
-        }
-
-        printk(KERN_INFO "%s: connected with remote side\n",dev->name);
-        ctc_clear_busy(dev);
-        return 0;
+		printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
+		
+		for (i = 0; i < 2;  i++) {
+			del_timer(&privptr->channel[i].timer);
+
+			for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS;  j++)
+				ctc_buffer_free(&privptr->channel[i]);
+
+			if (privptr->channel[i].free_anchor != NULL)
+				printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+							 dev->name, __FUNCTION__, CTC_BLOCKS);
+		}
+		return -EIO;
+	}
+
+	printk(KERN_INFO "%s: connected with remote side\n",dev->name);
+	ctc_clear_busy(dev);
+	MOD_INC_USE_COUNT;
+	return 0;
 }
 
 
-static void ctc_timer (struct channel *ctc)
-{
-#ifdef DEBUG
-        net_device  *dev;
-
-        dev = (net_device *) ctc->dev; 
-        printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
-#endif
-        ctc->flag |= CTC_TIMER;
-        wake_up(&ctc->wait);  
-        return;
+static void ctc_timer (unsigned long data)
+{
+	struct channel *ctc = (struct channel *) data;
+#ifdef DEBUG
+	net_device *dev = (net_device *) ctc->dev; 
+	printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
+#endif
+	ctc->flag |= (CTC_TIMER|CTC_WAKEUP);
+	wake_up(&ctc->wait);  
+	return;
 }  
 
 /*
@@ -1452,49 +1768,75 @@
  */
 static int ctc_release(net_device *dev)
 {   
-        int                rc;
-        int                i;
-        int                j;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        __u32              parm;
-        struct ctc_priv    *privptr;
-	DECLARE_WAITQUEUE(wait, current);
-
-        privptr = (struct ctc_priv *) dev->priv;  
-   
-	ctc_protect_busy_irqsave(dev,saveflags);
-        ctc_setbit_busy(TB_STOP,dev);    
-	ctc_unprotect_busy_irqrestore(dev,flags);
-        for (i = 0; i < 2;  i++) {
-                s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
-                del_timer(&privptr->channel[READ].timer);  
-                privptr->channel[i].state = CTC_STOP;
-                parm = (__u32) &privptr->channel[i]; 
-                rc = halt_IO (privptr->channel[i].irq, parm, flags );
-                add_wait_queue(&privptr->channel[i].wait, &wait);
-                current->state = TASK_INTERRUPTIBLE;
-                s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); 
-                schedule();
-                remove_wait_queue(&privptr->channel[i].wait, &wait);
-                if (rc != 0) {
-                        ccw_check_return_code(dev, rc);
-                }
-                 
-                for (j = 0; j < CTC_BLOCKS;  j++) {  
-                        ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor);
-                        ctc_buffer_free(&privptr->channel[i]); 
-                }
-        }
-
-        if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
-            ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
-                printk(KERN_WARNING "%s: channel problems during close - read: %02x -  write: %02x\n",
-                    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
-                return -EIO;
-        }
+	int		   rc;
+	int		   i;
+	int		   j;
+	__u8		   flags = 0x00;
+	unsigned long	   saveflags;
+	__u32		   parm;
+	struct ctc_priv	   *privptr;
+	struct timer_list  timer;
+
+	privptr = (struct ctc_priv *) dev->priv;  
+	
+	ctc_protect_busy_irqsave(dev, saveflags);
+	ctc_setbit_busy(TB_STOP,dev);	 
+	ctc_unprotect_busy_irqrestore(dev, saveflags);
+
+	for (i = 0; i < 2;  i++) {
+		privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER);
+		init_timer(&timer);
+		timer.function = ctc_timer; 
+		timer.data = (unsigned long)&privptr->channel[i];
+		timer.expires = jiffies + 300*HZ;			 /* time to connect with the remote side */
+		add_timer(&timer);
+
+		s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); 
+		del_timer(&privptr->channel[i].timer);
+		privptr->channel[i].state = CTC_STOP;
+		parm = (__u32)(long) &privptr->channel[i]; 
+		rc = halt_IO (privptr->channel[i].irq, parm, flags );	   
+		s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); 
+
+		wait_event(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+		del_timer(&timer);
+
+		if (rc != 0) {
+			ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+		}
+
+		if(privptr->channel[i].flag & CTC_TIMER)
+		{
+			printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n",
+						 dev->name, __FUNCTION__);
+		}
+		
+
+		for (j=0; privptr->channel[i].proc_anchor != NULL && j < CTC_BLOCKS; j++)
+			ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor, dev);
+
+		if (privptr->channel[i].proc_anchor != NULL)
+			printk(KERN_WARNING "%s: %s(): trying to move more than maximal number %d of blocks to free list\n",
+						 dev->name, __FUNCTION__, CTC_BLOCKS);
+
+		for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS;  j++)
+			ctc_buffer_free(&privptr->channel[i]);
+
+		if (privptr->channel[i].free_anchor != NULL)
+			printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+						 dev->name, __FUNCTION__, CTC_BLOCKS);
+	}
+
+	if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
+	    ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+		printk(KERN_WARNING "%s: channel problems during close - read: %02x -  write: %02x\n",
+		    dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+		return -EIO;
+	}
 
-        return 0;
+	MOD_DEC_USE_COUNT;
+	return 0;
 }  
 
 
@@ -1505,80 +1847,80 @@
  */
 static int ctc_tx(struct sk_buff *skb, net_device *dev)
 {
-        int                rc=0,rc2;
-        __u32              parm;
-        __u8               flags = 0x00;
-        __u32              saveflags;
-        struct ctc_priv    *privptr;
-        struct packet      *lp;
-   
+	int		   rc=0,rc2;
+	__u32		   parm;
+	__u8		   flags = 0x00;
+	unsigned long	   saveflags;
+	struct ctc_priv	   *privptr;
+	struct packet	   *lp;
+
    
-        privptr = (struct ctc_priv *) (dev->priv);
+	privptr = (struct ctc_priv *) (dev->priv);
 
-        if (skb == NULL) { 
-                printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
-                privptr->stats.tx_dropped++;
-                return -EIO;
-        }
-        
-        s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
-        if (ctc_check_busy(dev)) {
-                rc=-EBUSY;
+	if (skb == NULL) { 
+		printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
+		privptr->stats.tx_dropped++;
+		return -EIO;
+	}
+	
+	s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+	if (ctc_check_busy(dev)) {
+		rc=-EBUSY;
 		goto Done;
-        } 
+	} 
 
-        if (ctc_test_and_setbit_busy(TB_TX,dev)) {                /* set transmission to busy */
-                rc=-EBUSY;
+	if (ctc_test_and_setbit_busy(TB_TX,dev)) {		  /* set transmission to busy */
+		rc=-EBUSY;
 		goto Done;
-        } 
+	} 
 
-        if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) {
+	if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) {
 #ifdef DEBUG
-                printk(KERN_DEBUG "%s: early swap\n", dev->name);
+		printk(KERN_DEBUG "%s: early swap\n", dev->name);
 #endif
-               
-                ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor);
-                if (privptr->channel[WRITE].free_anchor == NULL){
-                        ctc_setbit_busy(TB_NOBUFFER,dev);
-                        rc=-EBUSY;
+	       
+		ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor, dev);
+		if (privptr->channel[WRITE].free_anchor == NULL){
+			ctc_setbit_busy(TB_NOBUFFER,dev);
+			rc=-EBUSY;
 			goto Done2;
-                }
-        }
-        
-        if (privptr->channel[WRITE].free_anchor->block->length == 0) {
-                privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; 
-                privptr->channel[WRITE].free_anchor->packets = 0;
-        } 
-
-
-        (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length;
-        privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
-        lp->length = skb->len + PACKET_HEADER_LENGTH; 
-        lp->type = 0x0800; 
-        lp->unused = 0;
-        memcpy(&lp->data, skb->data, skb->len); 
-        (__u8 *) lp += lp->length; 
-        lp->length = 0;
-        dev_kfree_skb(skb);
-        privptr->channel[WRITE].free_anchor->packets++;
-
-        if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) {
-                ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor); 
-                privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
-                privptr->channel[WRITE].ccw[1].cda   = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block);
-                parm = (__u32) &privptr->channel[WRITE];  
-                rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
-                if (rc2 != 0) 
-                        ccw_check_return_code(dev, rc2);
-                dev->trans_start = jiffies;
-        }
-        if (privptr->channel[WRITE].free_anchor == NULL)
-                ctc_setbit_busy(TB_NOBUFFER,dev);
+		}
+	}
+	
+	if (privptr->channel[WRITE].free_anchor->block->length == 0) {
+		privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; 
+		privptr->channel[WRITE].free_anchor->packets = 0;
+	} 
+
+
+	(__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length;
+	privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
+	lp->length = skb->len + PACKET_HEADER_LENGTH; 
+	lp->type = 0x0800; 
+	lp->unused = 0;
+	memcpy(&lp->data, skb->data, skb->len); 
+	(__u8 *) lp += lp->length; 
+	lp->length = 0;
+	dev_kfree_skb(skb);
+	privptr->channel[WRITE].free_anchor->packets++;
+
+	if (test_and_set_bit(0, &privptr->channel[WRITE].IO_active) == 0) {
+	       ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor, dev);
+		privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
+		privptr->channel[WRITE].ccw[1].cda   = __pa(privptr->channel[WRITE].proc_anchor->block);
+		parm = (__u32)(long) &privptr->channel[WRITE];  
+		rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
+		if (rc2 != 0) 
+			ccw_check_return_code(dev, rc2, __FUNCTION__ "()[1]");
+		dev->trans_start = jiffies;
+	}
+	if (privptr->channel[WRITE].free_anchor == NULL)
+		ctc_setbit_busy(TB_NOBUFFER,dev);
 Done2:
-        ctc_clearbit_busy(TB_TX,dev);
+	ctc_clearbit_busy(TB_TX,dev);
 Done:
 	s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
-        return(rc);
+	return(rc);
 } 
 
 
@@ -1586,15 +1928,15 @@
  *   ctc_change_mtu 
  *
  *   S/390 can handle MTU sizes from 576 to 32760 for VM, VSE
- *                                   576 to 65527 for OS/390
+ *				     576 to 65527 for OS/390
  *
  */
 static int ctc_change_mtu(net_device *dev, int new_mtu)
 {
-        if ((new_mtu < 576) || (new_mtu > 65528))
-                return -EINVAL;
-        dev->mtu = new_mtu;
-        return 0;
+	if ((new_mtu < 576) || (new_mtu > 65528))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
 }
 
 
@@ -1604,18 +1946,129 @@
  */
 struct net_device_stats *ctc_stats(net_device *dev)
 {
-         struct ctc_priv *privptr;
+	 struct ctc_priv *privptr;
    
-         privptr = dev->priv;
-         return &privptr->stats;
+	 privptr = dev->priv;
+	 return &privptr->stats;
 }  
 
-
 /* Module code goes here */
 
-/*
-                free_irq(privptr->channel[i].irq, privptr->channel[i].devstat);
-                kfree(privptr->channel[i].devstat); 
+#ifdef MODULE
+void cleanup_module(void) {
+	int m;
+	int i;
+	int c;
+
+	/* we are called if all interfaces are down only, so no need
+	 * to bother around with locking stuff
+	 */
+	for (m = 0; m < CHANNEL_MEDIA;	m++) {
+		for (i = 0; i < MAX_ADAPTERS;  i++)
+			if (ctc_adapter[m][i].netdev) {
+				struct ctc_priv *privptr = ctc_adapter[m][i].netdev->priv;
+
+				unregister_netdev(ctc_adapter[m][i].netdev);
+				for (c = 0; c < 2; c++) {
+					free_irq(privptr->channel[c].irq, privptr->channel[c].devstat);
+					kfree(privptr->channel[c].devstat);
+				}
+				kfree(privptr);
+				kfree(ctc_adapter[m][i].netdev);
+			}
+	}
+	printk(KERN_INFO "CTC driver unloaded\n");
+}
+
+static char *parse_opts(char *str, int *ints) {
+	char *cur = str;
+	int i = 1;
+
+	while (cur && (*cur == '-' || isdigit(*cur)) && i <= 10) {
+		ints[i++] = simple_strtoul(cur, NULL, 0);
+		if ((cur = strchr(cur, ',')) != NULL)
+			cur++;
+	}
+	ints[0] = i - 1;
+	return(cur);
+}
+
+int init_module(void) {
+	char *p = setup; /* This string is set by insmod, it is writeable */
+	int cnt;
+	int itype;
+	int activated;
+	int ints[10];
+
+	print_banner();
+
+	/**
+	 * Parse setup string just like in init/main.c
+	 */
+	while (p && *p) {
+		char *q = strstr(p, "ctc=");
+		if (q) {
+			/**
+			 * Found "ctc=" in string
+			 */
+			q += 4;
+			if ((p = parse_opts(q, ints))) {
+				/**
+				 * p is now pointing to the first non-number parameter
+				 *
+				 */
+				if ((q = strchr(p, ' ')))
+					*q = '\0';
+				ctc_setup(p, ints);
+				if (q)
+					p = q + 1;
+				else
+					p = NULL;
+			}
+		} else
+			p = NULL;
+	}
+
+	activated = 0;
+	for (itype = 0; itype < 2; itype++) {
+		cnt = 0;
+		do {
+			net_device *dev = kmalloc(sizeof(net_device) + 11 /* name + trailing zero */ , GFP_KERNEL);
+			if (!dev) {
+				return -ENOMEM;
+			}
+			memset((unsigned char *)dev, 0, sizeof(net_device));
+			dev->name = (unsigned char *)dev + sizeof(net_device);
+			sprintf(dev->name, "%s%d", (itype) ? "escon" : "ctc", cnt++);
+			if (ctc_probe(dev) == 0) {
+				if (register_netdev(dev) != 0) {
+					struct ctc_priv *privptr = dev->priv;
+					int m = extract_channel_media(dev->name);
+					int i = extract_channel_id(dev->name);
+
+					printk(KERN_WARNING "ctc: Couldn't register %s\n", dev->name);
+					free_irq(privptr->channel[READ].irq, privptr->channel[READ].devstat);
+					kfree(privptr->channel[READ].devstat);
+					free_irq(privptr->channel[WRITE].irq, privptr->channel[WRITE].devstat);
+					kfree(privptr->channel[WRITE].devstat);
+					channel_free(m, ctc_adapter[m][i].devno[READ]);
+					channel_free(m, ctc_adapter[m][i].devno[WRITE]);
+					kfree(dev->priv);
+					kfree(dev);
+				} else
+					activated++;
+			} else {
+				kfree(dev);
+				cnt = MAX_ADAPTERS;
+			}
+		} while (cnt < MAX_ADAPTERS);
+	}
+	if (!activated) {
+		printk(KERN_WARNING "ctc: No devices registered\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+#endif
 
-*/
 /* --- This is the END my friend --- */
diff -urN linux-2.2.18-pre20/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- linux-2.2.18-pre20/drivers/s390/net/iucv.c	Mon Sep  4 10:39:20 2000
+++ linux/drivers/s390/net/iucv.c	Mon Dec  3 22:14:17 2001
@@ -9,7 +9,7 @@
  * 
  *    
  *    2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *                Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *                Martin Schwidefsky (schwidefsky@de.ibm.com)
  *                Alan Altmark (Alan_Altmark@us.ibm.com)
  *                
 
@@ -504,12 +504,15 @@
   printk(   "iucv: extern_int_buffer:\n");
   dumpit((char *)&extern_int_buffer[0],40);
 #endif
-  
+
   if (extern_int_buffer->iptype == 0x01)
     dev = get_device_from_userid(&((char*) extern_int_buffer)[8]);
   else
     dev = get_device_from_pathid(extern_int_buffer->ippathid);
 
+  if (dev == NULL)
+    return;
+
   netif_enter_interrupt(dev);        /* lock ! */
   privptr = (struct iucv_priv *)(dev->priv);
   
@@ -608,7 +611,7 @@
       printk(  "message pending.\n");
 #endif
       rcvptr = &privptr->receive_buffer[0];
-      
+
       /* re-set receive buffer */
       memset(privptr->receive_buffer,0,privptr->receive_buffer_len);
       len = privptr->receive_buffer_len;
diff -urN linux-2.2.18-pre20/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
--- linux-2.2.18-pre20/drivers/sbus/char/envctrl.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/sbus/char/envctrl.c	Mon Dec  3 22:14:17 2001
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.9.2.1 2000/05/02 04:23:33 davem Exp $
+/* $Id: envctrl.c,v 1.9.2.2 2000/11/08 09:43:04 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -11,6 +11,9 @@
  * 	http://www-eu2.semiconductors.com/pip/PCF8584P
  * 	http://www-eu2.semiconductors.com/pip/PCF8574AP
  * 	http://www-eu2.semiconductors.com/pip/PCF8591P
+ *
+ * 	EB - Added support for CP1500 Global Address and PS/Voltage monitoring.
+ * 	     Eric Brower <ebrower@usa.net>
  * 
  */
 
@@ -74,15 +77,16 @@
  * Firmware definitions.
  */
 #define PCF8584_MAX_CHANNELS            8
+#define PCF8584_GLOBALADDR_TYPE			6  /* global address monitor */
 #define PCF8584_FANSTAT_TYPE            3  /* fan status monitor */
 #define PCF8584_VOLTAGE_TYPE            2  /* voltage monitor    */
-#define PCF8584_TEMP_TYPE	        1  /* temperature monitor*/
+#define PCF8584_TEMP_TYPE	        	1  /* temperature monitor*/
 
 /* Monitor type of i2c child device.
  * Driver definitions.
  */
-#define ENVCTRL_NOMON			0
-#define ENVCTRL_CPUTEMP_MON		1    /* cpu temperature monitor */
+#define ENVCTRL_NOMON				0
+#define ENVCTRL_CPUTEMP_MON			1    /* cpu temperature monitor */
 #define ENVCTRL_CPUVOLTAGE_MON	  	2    /* voltage monitor         */
 #define ENVCTRL_FANSTAT_MON  		3    /* fan status monitor      */
 #define ENVCTRL_ETHERTEMP_MON		4    /* ethernet temperarture */
@@ -90,6 +94,7 @@
 #define ENVCTRL_VOLTAGESTAT_MON	  	5    /* voltage status monitor  */
 #define ENVCTRL_MTHRBDTEMP_MON		6    /* motherboard temperature */
 #define ENVCTRL_SCSITEMP_MON		7    /* scsi temperarture */
+#define ENVCTRL_GLOBALADDR_MON		8    /* global address */
 
 /* Child device type.
  * Driver definitions.
@@ -111,6 +116,15 @@
 #define ENVCTRL_MAX_CPU			4
 #define CHANNEL_DESC_SZ			256
 
+/* Mask values for combined GlobalAddress/PowerStatus node */
+#define ENVCTRL_GLOBALADDR_ADDR_MASK	0x1F
+#define ENVCTRL_GLOBALADDR_PSTAT_MASK	0x60
+
+/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms
+ * (see envctrl_init_i2c_child)
+ */
+#define ENVCTRL_CPCI_IGNORED_NODE		0x70
+
 struct pcf8584_reg {
 	 unsigned char data;
 	 unsigned char csr;
@@ -198,7 +212,7 @@
 	int limit = 1000000;
 
 	while (--limit > 0) {
-		if(!(envctrl_readb(&i2c->csr) & STATUS_PIN)) 
+		if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) 
 			break;
 		udelay(1);
 	} 
@@ -472,6 +486,31 @@
 	return 1;
 }
 
+/* Function Description: Read global addressing line.
+ * Return : Always 1 byte. Status stored in bufdata.
+ */
+static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild,
+				  unsigned char data,
+				  char *bufdata)
+{
+	/* Translatation table is not necessary, as global
+	 * addr is the integer value of the GA# bits.
+	 *
+	 * NOTE: MSB is documented as zero, but I see it as '1' always....
+	 *
+	 * -----------------------------------------------
+	 * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 |
+	 * -----------------------------------------------
+	 * GA0 - GA4	integer value of Global Address (backplane slot#)
+	 * DEG			0 = cPCI Power supply output is starting to degrade
+	 * 				1 = cPCI Power supply output is OK
+	 * FAL			0 = cPCI Power supply has failed
+	 * 				1 = cPCI Power supply output is OK
+	 */
+	bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK);
+	return 1;
+}
+
 /* Function Description: Read voltage and power supply status.
  * Return : Always 1 byte. Status stored in bufdata.
  */
@@ -598,9 +637,19 @@
 		copy_to_user((unsigned char*)buf, data, ret);
 		break;
 
+	case ENVCTRL_RD_GLOBALADDRESS:
+		if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+			return 0;
+		data[0] = envctrl_i2c_read_8574(pchild->addr);
+		ret = envctrl_i2c_globaladdr(pchild, data[0], data);
+		copy_to_user((unsigned char*)buf, data, ret);
+		break;
+
 	case ENVCTRL_RD_VOLTAGE_STATUS:
 		if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON)))
-			return 0;
+			/* If voltage monitor not present, check for CPCI equivalent */
+			if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+				return 0;
 		data[0] = envctrl_i2c_read_8574(pchild->addr);
 		ret = envctrl_i2c_voltage_status(pchild, data[0], data);
 		copy_to_user((unsigned char*)buf, data, ret);
@@ -631,6 +680,7 @@
 	case ENVCTRL_RD_VOLTAGE_STATUS:
 	case ENVCTRL_RD_ETHERNET_TEMPERATURE:
 	case ENVCTRL_RD_SCSI_TEMPERATURE:
+	case ENVCTRL_RD_GLOBALADDRESS:
 		file->private_data = (void *)(long)cmd;
 		break;
 
@@ -729,9 +779,6 @@
 
 	if (!(strcmp(chnl_desc,"temp,ethernet")))
 		pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
-
-	if (!(strcmp(chnl_desc,"temp,ethernet")))
-		pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
 }
 
 /* Function Description: Initialize monitor channel with channel desc,
@@ -785,6 +832,39 @@
 	pchild->mon_type[0] = ENVCTRL_FANSTAT_MON;
 }
 
+/* Function Description: Initialize child device for global addressing line.
+ * Return: None.
+ */
+static void envctrl_init_globaladdr(struct i2c_child_t *pchild)
+{
+	int i;
+
+	/* Voltage/PowerSupply monitoring is piggybacked 
+	 * with Global Address on CompactPCI.  See comments
+	 * within envctrl_i2c_globaladdr for bit assignments.
+	 *
+	 * The mask is created here by assigning mask bits to each
+	 * bit position that represents PCF8584_VOLTAGE_TYPE data.
+	 * Channel numbers are not consecutive within the globaladdr
+	 * node (why?), so we use the actual counter value as chnls_mask
+	 * index instead of the chnl_array[x].chnl_no value.
+	 *
+	 * NOTE: This loop could be replaced with a constant representing
+	 * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK).
+	 */
+	for (i = 0; i < pchild->total_chnls; i++) {
+		if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) {
+			pchild->voltage_mask |= chnls_mask[i];
+		}
+	}
+
+	/* We only need to know if this child has global addressing 
+	 * line monitored.  We dont care which channels since we know 
+	 * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK).
+	 */
+	pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON;
+}
+
 /* Initialize child device monitoring voltage status. */
 static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
 {
@@ -832,6 +912,26 @@
 		}
 	}
 
+	/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
+	 * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is
+	 * "For Factory Use Only."
+	 *
+	 * We ignore the node on these platforms by assigning the
+	 * 'NULL' monitor type.
+	 */
+	if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+		int len;
+		char prop[56];
+
+		len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
+		if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) {
+			for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
+				pchild->mon_type[len] = ENVCTRL_NOMON;
+			}
+			return;
+		}
+	}
+
 	/* Get the monitor channels. */
 	len = prom_getproperty(node, "channels-in-use", (char *)pchild->chnl_array,
 			       PCF8584_MAX_CHANNELS*sizeof(struct pcf8584_channel));
@@ -843,6 +943,11 @@
 			envctrl_init_adc(pchild, node);
 			break;
 
+		case PCF8584_GLOBALADDR_TYPE:
+			envctrl_init_globaladdr(pchild);
+			i = pchild->total_chnls;
+			break;
+
 		case PCF8584_FANSTAT_TYPE:
 			envctrl_init_fanstat(pchild);
 			i = pchild->total_chnls;
@@ -940,6 +1045,18 @@
 	if (misc_register(&envctrl_dev)) {
 		printk("envctrl: Unable to get misc minor %d\n",
 		       envctrl_dev.minor);
+	}
+
+	/* Note above traversal routine post-incremented 'i' to accomodate 
+	 * a next child device, so we decrement before reverse-traversal of
+	 * child devices.
+	 */
+	printk("envctrl: initialized ");
+	for (--i; i >= 0; --i) {
+		printk("[%s 0x%lx]%s", 
+			(I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : 
+			((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), 
+			i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
 	}
 
 	return 0;
diff -urN linux-2.2.18-pre20/drivers/sound/awacs_defs.h linux/drivers/sound/awacs_defs.h
--- linux-2.2.18-pre20/drivers/sound/awacs_defs.h	Wed Mar 10 21:48:46 1999
+++ linux/drivers/sound/awacs_defs.h	Mon Dec  3 22:14:17 2001
@@ -62,12 +62,18 @@
 #define MASK_ADDR_VOLC	MASK_ADDR4	/* Volume Control C -- Speaker */
 #define MASK_ADDR_VOLSPK MASK_ADDR4
 
+/* additional registers of screamer */
+#define MASK_ADDR5	(0x5 << 12)	/* Expanded Data Mode Address 5 */
+#define MASK_ADDR6	(0x6 << 12)	/* Expanded Data Mode Address 6 */
+#define MASK_ADDR7	(0x7 << 12)	/* Expanded Data Mode Address 7 */
+
+
 /* Address 0 Bit Masks & Macros */
 /* ------- - --- ----- - ------ */
 #define MASK_GAINRIGHT	(0xf)		/* Gain Right Mask */
 #define MASK_GAINLEFT	(0xf << 4)	/* Gain Left Mask */
-#define MASK_GAINLINE	(0x1 << 8)	/* Change Gain for Line??? */
-#define MASK_GAINMIC	(0x0 << 8)	/* Change Gain for Mic??? */
+#define MASK_GAINLINE	(0x1 << 8)	/* Disable Mic preamp */
+#define MASK_GAINMIC	(0x0 << 8)	/* Enable Mic preamp */
 
 #define MASK_MUX_CD	(0x1 << 9)	/* Select CD in MUX */
 #define MASK_MUX_MIC	(0x1 << 10)	/* Select Mic in MUX */
diff -urN linux-2.2.18-pre20/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- linux-2.2.18-pre20/drivers/sound/dmasound.c	Mon Sep  4 10:39:21 2000
+++ linux/drivers/sound/dmasound.c	Mon Dec  3 22:14:17 2001
@@ -179,6 +179,9 @@
 static struct device_node* awacs_node;
 
 static int awacs_revision;
+int awacs_is_screamer = 0;
+int awacs_device_id = 0;
+int awacs_has_iic = 0;
 #define AWACS_BURGUNDY	100		/* fake revision # for burgundy */
 
 /*
@@ -191,7 +194,7 @@
  * Cached values of AWACS registers (we can't read them).
  * Except on the burgundy. XXX
  */
-int awacs_reg[5];
+int awacs_reg[8];
 
 #define HAS_16BIT_TABLES
 #undef HAS_8BIT_TABLES
@@ -3400,6 +3403,11 @@
 		awacs_write(awacs_reg[1] | MASK_ADDR1);
 		awacs_write(awacs_reg[2] | MASK_ADDR2);
 		awacs_write(awacs_reg[4] | MASK_ADDR4);
+		if (awacs_is_screamer) {
+			awacs_write(awacs_reg[5] + MASK_ADDR5);
+			awacs_write(awacs_reg[6] + MASK_ADDR6);
+			awacs_write(awacs_reg[7] + MASK_ADDR7);
+		}
 		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
 		enable_irq(awacs_irq);
 		enable_irq(awacs_tx_irq);
@@ -4702,7 +4710,7 @@
 			size = bufSize << 10;
 		sq_setup(numBufs, size, sound_buffers);
 		sq.max_active = nbufs;
-		return 0;
+		return IOCTL_OUT(arg,size | numBufs << 16);
 	case SNDCTL_DSP_GETOSPACE:
 		info.fragments = sq.max_active - sq.count;
 		info.fragstotal = sq.max_active;
@@ -4711,9 +4719,11 @@
 		if (copy_to_user((void *)arg, &info, sizeof(info)))
 			return -EFAULT;
 		return 0;
-
-	default:
-		return mixer_ioctl(inode, file, cmd, arg);
+	case SNDCTL_DSP_GETCAPS:
+		data = 1;	/* Revision level of this ioctl() */
+		return IOCTL_OUT(arg, data);
+ 	default:
+ 		return mixer_ioctl(inode, file, cmd, arg);
 	}
 	return -EINVAL;
 }
@@ -5015,7 +5025,14 @@
 				awacs_subframe = *prop;
 			if (device_is_compatible(sound, "burgundy"))
 				awacs_revision = AWACS_BURGUNDY;
-
+			/* This should be verified on older screamers */
+			if (device_is_compatible(sound, "screamer"))
+				awacs_is_screamer = 1;
+			prop = (unsigned int *)get_property(sound, "device-id", 0);
+			if (prop != 0)
+				awacs_device_id = *prop;
+			awacs_has_iic = (find_devices("perch") != NULL);
+			
 			/* look for a property saying what sample rates
 			   are available */
 			for (i = 0; i < 8; ++i)
@@ -5077,17 +5094,29 @@
 		awacs_tx_cmds = (volatile struct dbdma_cmd *)
 			DBDMA_ALIGN(awacs_tx_cmd_space);
 		awacs_reg[0] = MASK_MUX_CD;
-		awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+		/* FIXME: Only machines with external SRS module need MASK_PAROUT */
+		awacs_reg[1] = MASK_LOOPTHRU;
+		if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8
+			|| */awacs_device_id == 0xb)
+			awacs_reg[1] |= MASK_PAROUT;
 		/* get default volume from nvram */
 		vol = (~nvram_read_byte(0x1308) & 7) << 1;
 		awacs_reg[2] = vol + (vol << 6);
 		awacs_reg[4] = vol + (vol << 6);
+		awacs_reg[5] = 0;
+		awacs_reg[6] = 0;
+		awacs_reg[7] = 0;
 		out_le32(&awacs->control, 0x11);
 		awacs_write(awacs_reg[0] + MASK_ADDR0);
 		awacs_write(awacs_reg[1] + MASK_ADDR1);
 		awacs_write(awacs_reg[2] + MASK_ADDR2);
 		awacs_write(awacs_reg[4] + MASK_ADDR4);
-
+		if (awacs_is_screamer) {
+			awacs_write(awacs_reg[5] + MASK_ADDR5);
+			awacs_write(awacs_reg[6] + MASK_ADDR6);
+			awacs_write(awacs_reg[7] + MASK_ADDR7);
+		}
+		
 		/* Initialize recent versions of the awacs */
 		if (awacs_revision == 0) {
 			awacs_revision =
diff -urN linux-2.2.18-pre20/drivers/usb/Config.in linux/drivers/usb/Config.in
--- linux-2.2.18-pre20/drivers/usb/Config.in	Mon Dec  3 22:14:09 2001
+++ linux/drivers/usb/Config.in	Mon Dec  3 22:14:17 2001
@@ -49,6 +49,7 @@
          fi
          dep_tristate '    USB Digi International AccelePort USB Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
          dep_tristate '    USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
+         dep_tristate '    USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
       fi
       bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
    fi
diff -urN linux-2.2.18-pre20/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c
--- linux-2.2.18-pre20/drivers/usb/keybdev.c	Mon Dec  3 22:14:09 2001
+++ linux/drivers/usb/keybdev.c	Mon Dec  3 22:14:17 2001
@@ -37,7 +37,7 @@
 #include <linux/kbd_kern.h>
 #include <linux/kcomp.h>
 
-#if defined(__i386__) || defined(__alpha__) || defined(__mips__)
+#if defined(__i386__) || defined(__alpha__) || defined(__mips__) || defined(__powerpc__)
 
 static int x86_sysrq_alt = 0;
 
@@ -59,8 +59,45 @@
 	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372
 };
 
+#ifdef CONFIG_INPUT_ADBHID
+extern int mac_hid_keyboard_sends_linux_keycodes(void);
+
+static unsigned char mac_keycodes[256] = {
+	  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
+	 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
+	  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
+	 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
+	 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
+	 84, 85, 82, 65, 42,  0, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
+	 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117,
+	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0, 95, 55, 55,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102
+};
+
+#ifdef CONFIG_INPUT_MOUSEDEV
+extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
+#endif /* CONFIG_INPUT_MOUSEDEV */
+#endif /* CONFIG_INPUT_ADBHID */
+
 static int emulate_raw(unsigned int keycode, int down)
 {
+#ifdef CONFIG_INPUT_ADBHID
+#ifdef CONFIG_INPUT_MOUSEDEV
+	if (mac_hid_mouse_emulate_buttons(1, keycode, down))
+		return 0;
+#endif /* CONFIG_INPUT_MOUSEDEV */
+	if (!mac_hid_keyboard_sends_linux_keycodes()) {
+		if (keycode > 255 || !mac_keycodes[keycode])
+			return -1;
+
+		handle_scancode(mac_keycodes[keycode] & 0x7f, down);
+
+		return 0;
+	}
+#endif /* CONFIG_INPUT_ADBHID */
 	if (keycode > 255 || !x86_keycodes[keycode])
 		return -1; 
 
@@ -88,28 +125,6 @@
 
 	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
 		x86_sysrq_alt = down;
-
-	return 0;
-}
-
-#elif defined(CONFIG_MAC_KEYBOARD)
-
-static unsigned char mac_keycodes[128] =
-	{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
-	 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
-	  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
-	 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
-	 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
-	 84, 85, 82, 65, 42,  0, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
-	 76,125, 75,105,124,  0,115, 62,116, 59, 60,119, 61,121,114,117,
-	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0,  0, 55, 55 };
-
-static int emulate_raw(unsigned int keycode, int down)
-{
-	if (keycode > 127 || !mac_keycodes[keycode])
-		return -1;
-
-	handle_scancode(mac_keycodes[keycode] & 0x7f, down);
 
 	return 0;
 }
diff -urN linux-2.2.18-pre20/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- linux-2.2.18-pre20/drivers/usb/serial/Makefile	Mon Dec  3 22:14:09 2001
+++ linux/drivers/usb/serial/Makefile	Mon Dec  3 22:14:18 2001
@@ -22,6 +22,7 @@
 obj-$(CONFIG_USB_SERIAL_KEYSPAN)		+= keyspan.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT)	+= digi_acceleport.o
+obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
  
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -urN linux-2.2.18-pre20/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- linux-2.2.18-pre20/drivers/usb/serial/belkin_sa.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/belkin_sa.c	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,561 @@
+/*
+ * Belkin USB Serial Adapter Driver
+ *
+ *  Copyright (C) 2000
+ *      William Greathouse (wgreathouse@smva.com)
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *  
+ * 	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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * TODO:
+ * -- Add true modem contol line query capability.  Currently we track the
+ *    states reported by the interrupt and the states we request.
+ * -- Add error reporting back to application for UART error conditions.
+ *    Just point me at how to implement this and I'll do it. I've put the
+ *    framework in, but haven't analyzed the "tty_flip" interface yet.
+ * -- Add support for flush commands
+ * -- Add everything that is missing :)
+ *
+ * (11/06/2000) gkh
+ *	- Added support for the old Belkin and Peracom devices.
+ *	- Made the port able to be opened multiple times.
+ *	- Added some defaults incase the line settings are things these devices
+ *	  can't support. 
+ *
+ * 18-Oct-2000 William Greathouse
+ *    Released into the wild (linux-usb-devel)
+ *
+ * 17-Oct-2000 William Greathouse
+ *    Add code to recognize firmware version and set hardware flow control
+ *    appropriately.  Belkin states that firmware prior to 3.05 does not
+ *    operate correctly in hardware handshake mode.  I have verified this
+ *    on firmware 2.05 -- for both RTS and DTR input flow control, the control
+ *    line is not reset.  The test performed by the Belkin Win* driver is
+ *    to enable hardware flow control for firmware 2.06 or greater and
+ *    for 1.00 or prior.  I am only enabling for 2.06 or greater.
+ *
+ * 12-Oct-2000 William Greathouse
+ *    First cut at supporting Belkin USB Serial Adapter F5U103
+ *    I did not have a copy of the original work to support this
+ *    adapter, so pardon any stupid mistakes.  All of the information
+ *    I am using to write this driver was acquired by using a modified
+ *    UsbSnoop on Windows2000 and from examining the other USB drivers.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ 	#define DEBUG
+#else
+ 	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+#include "belkin_sa.h"
+
+/* function prototypes for a Belkin USB Serial Adapter F5U103 */
+static int  belkin_sa_startup		(struct usb_serial *serial);
+static void belkin_sa_shutdown		(struct usb_serial *serial);
+static int  belkin_sa_open		(struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_close		(struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_read_int_callback (struct urb *urb);
+static void belkin_sa_set_termios	(struct usb_serial_port *port, struct termios * old);
+static int  belkin_sa_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void belkin_sa_break_ctl		(struct usb_serial_port *port, int break_state );
+
+/* All of the device info needed for the Belkin serial converter */
+static __u16	belkin_sa_vendor_id	= BELKIN_SA_VID;
+static __u16	belkin_sa_product_id	= BELKIN_SA_PID;
+struct usb_serial_device_type belkin_sa_device = {
+	name:			"Belkin F5U103 USB Serial Adapter",
+	idVendor:		&belkin_sa_vendor_id,		/* the Belkin vendor ID */
+	idProduct:		&belkin_sa_product_id,		/* the Belkin F5U103 product id */
+	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			belkin_sa_open,
+	close:			belkin_sa_close,
+	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
+	ioctl:			belkin_sa_ioctl,
+	set_termios:		belkin_sa_set_termios,
+	break_ctl:		belkin_sa_break_ctl,
+	startup:		belkin_sa_startup,
+	shutdown:		belkin_sa_shutdown,
+};
+
+
+/* This driver also supports the "old" school Belkin single port adaptor */
+static __u16	belkin_old_vendor_id	= BELKIN_OLD_VID;
+static __u16	belkin_old_product_id	= BELKIN_OLD_PID;
+struct usb_serial_device_type belkin_old_device = {
+	name:			"Belkin USB Serial Adapter",
+	idVendor:		&belkin_old_vendor_id,		/* the Belkin vendor ID */
+	idProduct:		&belkin_old_product_id,		/* the Belkin product id */
+	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			belkin_sa_open,
+	close:			belkin_sa_close,
+	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
+	ioctl:			belkin_sa_ioctl,
+	set_termios:		belkin_sa_set_termios,
+	break_ctl:		belkin_sa_break_ctl,
+	startup:		belkin_sa_startup,
+	shutdown:		belkin_sa_shutdown,
+};
+
+/* this driver also works for the Peracom single port adapter */
+static __u16	peracom_vendor_id	= PERACOM_VID;
+static __u16	peracom_product_id	= PERACOM_PID;
+struct usb_serial_device_type peracom_device = {
+	name:			"Peracom single port USB Serial Adapter",
+	idVendor:		&peracom_vendor_id,		/* the Peracom vendor ID */
+	idProduct:		&peracom_product_id,		/* the Peracom product id */
+	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			belkin_sa_open,
+	close:			belkin_sa_close,
+	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
+	ioctl:			belkin_sa_ioctl,
+	set_termios:		belkin_sa_set_termios,
+	break_ctl:		belkin_sa_break_ctl,
+	startup:		belkin_sa_startup,
+	shutdown:		belkin_sa_shutdown,
+};
+
+
+struct belkin_sa_private {
+	unsigned long		control_state;
+	unsigned char		last_lsr;
+	unsigned char		last_msr;
+	int			bad_flow_control;
+};
+
+
+/*
+ * ***************************************************************************
+ * Belkin USB Serial Adapter F5U103 specific driver functions
+ * ***************************************************************************
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* assumes that struct usb_serial *serial is available */
+#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \
+					    (c), BELKIN_SA_SET_REQUEST_TYPE, \
+					    (v), 0, NULL, 0, WDR_TIMEOUT)
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int belkin_sa_startup (struct usb_serial *serial)
+{
+	struct usb_device *dev = serial->dev;
+	struct belkin_sa_private *priv;
+
+	/* allocate the private data structure */
+	serial->port->private = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL);
+	if (!serial->port->private)
+		return (-1); /* error */
+	priv = (struct belkin_sa_private *)serial->port->private;
+	/* set initial values for control structures */
+	priv->control_state = 0;
+	priv->last_lsr = 0;
+	priv->last_msr = 0;
+	/* see comments at top of file */
+	priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0;
+	info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control);
+
+	init_waitqueue_head(&serial->port->write_wait);
+	
+	return (0);
+}
+
+
+static void belkin_sa_shutdown (struct usb_serial *serial)
+{
+	int i;
+	
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			belkin_sa_close (&serial->port[i], NULL);
+		}
+		/* My special items, the standard routines free my urbs */
+		if (serial->port->private)
+			kfree(serial->port->private);
+	}
+}
+
+
+static int  belkin_sa_open (struct usb_serial_port *port, struct file *filp)
+{
+	unsigned long flags;
+
+	dbg(__FUNCTION__" port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+	
+	++port->open_count;
+	MOD_INC_USE_COUNT;
+	
+	if (!port->active) {
+		port->active = 1;
+
+		/*Start reading from the device*/
+		/* TODO: Look at possibility of submitting mulitple URBs to device to
+		 *       enhance buffering.  Win trace shows 16 initial read URBs.
+		 */
+		port->read_urb->dev = port->serial->dev;
+		if (usb_submit_urb(port->read_urb))
+			err("usb_submit_urb(read bulk) failed");
+
+		port->interrupt_in_urb->dev = port->serial->dev;
+		if (usb_submit_urb(port->interrupt_in_urb))
+			err(" usb_submit_urb(read int) failed");
+	}
+	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	return 0;
+} /* belkin_sa_open */
+
+
+static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
+{
+	unsigned long flags;
+
+	dbg(__FUNCTION__" port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	--port->open_count;
+	MOD_DEC_USE_COUNT;
+
+	if (port->open_count <= 0) {
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);	/* wgg - do I need this? I think so. */
+		port->active = 0;
+	}
+	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+} /* belkin_sa_close */
+
+
+static void belkin_sa_read_int_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+	struct usb_serial *serial;
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+
+	/* the urb might have been killed. */
+	if (urb->status)
+		return;
+	
+	if (port_paranoia_check (port, "belkin_sa_read_interrupt")) return;
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "belkin_sa_read_interrupt")) return;
+	
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+	/* Handle known interrupt data */
+	/* ignore data[0] and data[1] */
+
+	priv->last_msr = data[BELKIN_SA_MSR_INDEX];
+	
+	/* Record Control Line states */
+	if (priv->last_msr & BELKIN_SA_MSR_DSR)
+		priv->control_state |= TIOCM_DSR;
+	else
+		priv->control_state &= ~TIOCM_DSR;
+
+	if (priv->last_msr & BELKIN_SA_MSR_CTS)
+		priv->control_state |= TIOCM_CTS;
+	else
+		priv->control_state &= ~TIOCM_CTS;
+
+	if (priv->last_msr & BELKIN_SA_MSR_RI)
+		priv->control_state |= TIOCM_RI;
+	else
+		priv->control_state &= ~TIOCM_RI;
+
+	if (priv->last_msr & BELKIN_SA_MSR_CD)
+		priv->control_state |= TIOCM_CD;
+	else
+		priv->control_state &= ~TIOCM_CD;
+
+	/* Now to report any errors */
+	priv->last_lsr = data[BELKIN_SA_LSR_INDEX];
+#if 0
+	/*
+	 * fill in the flip buffer here, but I do not know the relation
+	 * to the current/next receive buffer or characters.  I need
+	 * to look in to this before committing any code.
+	 */
+	if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
+		tty = port->tty;
+		/* Overrun Error */
+		if (priv->last_lsr & BELKIN_SA_LSR_OE) {
+		}
+		/* Parity Error */
+		if (priv->last_lsr & BELKIN_SA_LSR_PE) {
+		}
+		/* Framing Error */
+		if (priv->last_lsr & BELKIN_SA_LSR_FE) {
+		}
+		/* Break Indicator */
+		if (priv->last_lsr & BELKIN_SA_LSR_BI) {
+		}
+	}
+#endif
+
+	/* INT urbs are automatically re-submitted */
+}
+
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	struct usb_serial *serial = port->serial;
+	struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+	unsigned int iflag = port->tty->termios->c_iflag;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int old_iflag = old_termios->c_iflag;
+	unsigned int old_cflag = old_termios->c_cflag;
+	__u16 urb_value; /* Will hold the new flags */
+	
+	/* Set the baud rate */
+	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+		/* reassert DTR and (maybe) RTS on transition from B0 */
+		if( (old_cflag&CBAUD) == B0 ) {
+			priv->control_state |= (TIOCM_DTR|TIOCM_RTS);
+			if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
+				err("Set DTR error");
+			/* don't set RTS if using hardware flow control */
+			if (!(old_cflag&CRTSCTS) )
+				if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
+					err("Set RTS error");
+		}
+
+		switch(cflag & CBAUD) {
+			case B0: /* handled below */ break;
+			case B300: urb_value = BELKIN_SA_BAUD(300); break;
+			case B600: urb_value = BELKIN_SA_BAUD(600); break;
+			case B1200: urb_value = BELKIN_SA_BAUD(1200); break;
+			case B2400: urb_value = BELKIN_SA_BAUD(2400); break;
+			case B4800: urb_value = BELKIN_SA_BAUD(4800); break;
+			case B9600: urb_value = BELKIN_SA_BAUD(9600); break;
+			case B19200: urb_value = BELKIN_SA_BAUD(19200); break;
+			case B38400: urb_value = BELKIN_SA_BAUD(38400); break;
+			case B57600: urb_value = BELKIN_SA_BAUD(57600); break;
+			case B115200: urb_value = BELKIN_SA_BAUD(115200); break;
+			case B230400: urb_value = BELKIN_SA_BAUD(230400); break;
+			default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600");
+				urb_value = BELKIN_SA_BAUD(9600); break;
+		}
+		if ((cflag & CBAUD) != B0 ) {
+			if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
+				err("Set baudrate error");
+		} else {
+			/* Disable flow control */
+			if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
+				err("Disable flowcontrol error");
+
+			/* Drop RTS and DTR */
+			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+			if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
+				err("DTR LOW error");
+			if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
+				err("RTS LOW error");
+		}
+	}
+
+	/* set the parity */
+	if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
+		if (cflag & PARENB)
+			urb_value = (cflag & PARODD) ?  BELKIN_SA_PARITY_ODD : BELKIN_SA_PARITY_EVEN;
+		else
+			urb_value = BELKIN_SA_PARITY_NONE;
+		if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0)
+			err("Set parity error");
+	}
+
+	/* set the number of data bits */
+	if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
+		switch (cflag & CSIZE) {
+			case CS5: urb_value = BELKIN_SA_DATA_BITS(5); break;
+			case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
+			case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
+			case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
+			default: err("CSIZE was not CS5-CS8, using default of 8");
+				urb_value = BELKIN_SA_DATA_BITS(8);
+				break;
+		}
+		if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0)
+			err("Set data bits error");
+	}
+
+	/* set the number of stop bits */
+	if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+		urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) : BELKIN_SA_STOP_BITS(1);
+		if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, urb_value) < 0)
+			err("Set stop bits error");
+	}
+
+	/* Set flow control */
+	if( (iflag&IXOFF)   != (old_iflag&IXOFF)
+	||	(iflag&IXON)    != (old_iflag&IXON)
+	||  (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
+		urb_value = 0;
+		if ((iflag & IXOFF) || (iflag & IXON))
+			urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON);
+		else
+			urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON);
+
+		if (cflag & CRTSCTS)
+			urb_value |=  (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
+		else
+			urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
+
+		if (priv->bad_flow_control)
+			urb_value &= ~(BELKIN_SA_FLOW_IRTS);
+
+		if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0)
+			err("Set flow control error");
+	}
+} /* belkin_sa_set_termios */
+
+
+static void belkin_sa_break_ctl( struct usb_serial_port *port, int break_state )
+{
+	struct usb_serial *serial = port->serial;
+
+	if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0)
+		err("Set break_ctl %d", break_state);
+}
+
+
+static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	__u16 urb_value; /* Will hold the new flags */
+	struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+	int  ret, mask;
+	
+	/* Based on code from acm.c and others */
+	switch (cmd) {
+	case TIOCMGET:
+		return put_user(priv->control_state, (unsigned long *) arg);
+		break;
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+			/* RTS needs set */
+			urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0;
+			if (urb_value)
+				priv->control_state |= TIOCM_RTS;
+			else
+				priv->control_state &= ~TIOCM_RTS;
+
+			if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) {
+				err("Set RTS error %d", ret);
+				return(ret);
+			}
+		}
+
+		if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+			/* DTR needs set */
+			urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0;
+			if (urb_value)
+				priv->control_state |= TIOCM_DTR;
+			else
+				priv->control_state &= ~TIOCM_DTR;
+			if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) {
+				err("Set DTR error %d", ret);
+				return(ret);
+			}
+		}
+		break;
+					
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+		return( 0 );
+
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		/* TODO */
+		return 0;
+
+	default:
+		dbg("belkin_sa_ioctl arg not supported - 0x%04x",cmd);
+		return(-ENOIOCTLCMD);
+		break;
+	}
+	return 0;
+} /* belkin_sa_ioctl */
+
+
+static int __init belkin_sa_init (void)
+{
+	usb_serial_register (&belkin_sa_device);
+	usb_serial_register (&belkin_old_device);
+	usb_serial_register (&peracom_device);
+	return 0;
+}
+
+
+static void __exit belkin_sa_exit (void)
+{
+	usb_serial_deregister (&belkin_sa_device);
+	usb_serial_deregister (&belkin_old_device);
+	usb_serial_deregister (&peracom_device);
+}
+
+
+module_init (belkin_sa_init);
+module_exit(belkin_sa_exit);
+
+MODULE_DESCRIPTION("USB Belkin Serial converter driver");
diff -urN linux-2.2.18-pre20/drivers/usb/serial/belkin_sa.h linux/drivers/usb/serial/belkin_sa.h
--- linux-2.2.18-pre20/drivers/usb/serial/belkin_sa.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/belkin_sa.h	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,113 @@
+/*
+ * Definitions for Belkin USB Serial Adapter Driver
+ *
+ *  Copyright (C) 2000
+ *      William Greathouse (wgreathouse@smva.com)
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *  
+ * 	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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (11/06/2000) gkh
+ *	Added old Belkin and Peracom device ids, which this driver supports
+ *
+ * 12-Oct-2000 William Greathouse
+ *    First cut at supporting Belkin USB Serial Adapter F5U103
+ *    I did not have a copy of the original work to support this
+ *    adapter, so pardon any stupid mistakes.  All of the information
+ *    I am using to write this driver was acquired by using a modified
+ *    UsbSnoop on Windows2000.
+ *    
+ */
+
+#ifndef __LINUX_USB_SERIAL_BSA_H
+#define __LINUX_USB_SERIAL_BSA_H
+
+#define BELKIN_SA_VID	0x050d	/* Vendor Id */
+#define BELKIN_SA_PID	0x0103	/* Product Id */
+
+#define BELKIN_OLD_VID	0x056c	/* Belkin's "old" vendor id */
+#define BELKIN_OLD_PID	0x8007	/* Belkin's "old" single port serial converter's id */
+
+#define PERACOM_VID	0x0565	/* Peracom's vendor id */
+#define PERACOM_PID	0x0001	/* Peracom's single port serial converter's id */
+
+/* Vendor Request Interface */
+#define BELKIN_SA_SET_BAUDRATE_REQUEST	0  /* Set baud rate */
+#define BELKIN_SA_SET_STOP_BITS_REQUEST	1  /* Set stop bits (1,2) */
+#define BELKIN_SA_SET_DATA_BITS_REQUEST	2  /* Set data bits (5,6,7,8) */
+#define BELKIN_SA_SET_PARITY_REQUEST	3  /* Set parity (None, Even, Odd) */
+
+#define BELKIN_SA_SET_DTR_REQUEST	10 /* Set DTR state */
+#define BELKIN_SA_SET_RTS_REQUEST	11 /* Set RTS state */
+#define BELKIN_SA_SET_BREAK_REQUEST	12 /* Set BREAK state */
+
+#define BELKIN_SA_SET_FLOW_CTRL_REQUEST	16 /* Set flow control mode */
+
+
+#ifdef WHEN_I_LEARN_THIS
+#define BELKIN_SA_SET_MAGIC_REQUEST	17 /* I don't know, possibly flush */
+					   /* (always in Wininit sequence before flow control) */
+#define BELKIN_SA_RESET 		xx /* Reset the port */
+#define BELKIN_SA_GET_MODEM_STATUS	xx /* Force return of modem status register */
+#endif
+
+#define BELKIN_SA_SET_REQUEST_TYPE	0x40
+
+#define BELKIN_SA_BAUD(b)		(230400/b)
+
+#define BELKIN_SA_STOP_BITS(b)		(b-1)
+
+#define BELKIN_SA_DATA_BITS(b)		(b-5)
+
+#define BELKIN_SA_PARITY_NONE		0
+#define BELKIN_SA_PARITY_EVEN		1
+#define BELKIN_SA_PARITY_ODD		2
+#define BELKIN_SA_PARITY_MARK		3
+#define BELKIN_SA_PARITY_SPACE		4
+
+#define BELKIN_SA_FLOW_NONE		0x0000	/* No flow control */
+#define BELKIN_SA_FLOW_OCTS		0x0001	/* use CTS input to throttle output */
+#define BELKIN_SA_FLOW_ODSR		0x0002	/* use DSR input to throttle output */
+#define BELKIN_SA_FLOW_IDSR		0x0004	/* use DSR input to enable receive */
+#define BELKIN_SA_FLOW_IDTR		0x0008	/* use DTR output for input flow control */
+#define BELKIN_SA_FLOW_IRTS		0x0010	/* use RTS output for input flow control */
+#define BELKIN_SA_FLOW_ORTS		0x0020	/* use RTS to indicate data available to send */
+#define BELKIN_SA_FLOW_ERRSUB		0x0040	/* ???? guess ???? substitute inline errors */
+#define BELKIN_SA_FLOW_OXON		0x0080	/* use XON/XOFF for output flow control */
+#define BELKIN_SA_FLOW_IXON		0x0100	/* use XON/XOFF for input flow control */
+
+/*
+ * It seems that the interrupt pipe is closely modelled after the
+ * 16550 register layout.  This is probably because the adapter can 
+ * be used in a "DOS" environment to simulate a standard hardware port.
+ */
+#define BELKIN_SA_LSR_INDEX		2		/* Line Status Register */
+#define BELKIN_SA_LSR_RDR		0x01	/* receive data ready */
+#define BELKIN_SA_LSR_OE		0x02	/* overrun error */
+#define BELKIN_SA_LSR_PE		0x04	/* parity error */
+#define BELKIN_SA_LSR_FE		0x08	/* framing error */
+#define BELKIN_SA_LSR_BI		0x10	/* break indicator */
+#define BELKIN_SA_LSR_THE		0x20	/* transmit holding register empty */
+#define BELKIN_SA_LSR_TE		0x40	/* transmit register empty */
+#define BELKIN_SA_LSR_ERR		0x80	/* OE | PE | FE | BI */
+
+#define BELKIN_SA_MSR_INDEX		3		/* Modem Status Register */
+#define BELKIN_SA_MSR_DCTS		0x01	/* Delta CTS */
+#define BELKIN_SA_MSR_DDSR		0x02	/* Delta DSR */
+#define BELKIN_SA_MSR_DRI		0x04	/* Delta RI */
+#define BELKIN_SA_MSR_DCD		0x08	/* Delta CD */
+#define BELKIN_SA_MSR_CTS		0x10	/* Current CTS */
+#define BELKIN_SA_MSR_DSR		0x20	/* Current DSR */
+#define BELKIN_SA_MSR_RI		0x40	/* Current RI */
+#define BELKIN_SA_MSR_CD		0x80	/* Current CD */
+
+#endif /* __LINUX_USB_SERIAL_BSA_H */
+
diff -urN linux-2.2.18-pre20/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- linux-2.2.18-pre20/drivers/usb/usb-ohci.c	Mon Dec  3 22:14:09 2001
+++ linux/drivers/usb/usb-ohci.c	Mon Dec  3 22:14:18 2001
@@ -56,10 +56,13 @@
 
 #include <linux/pm.h>
 static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
+static void dl_del_list (ohci_t  * ohci, unsigned int frame);
 
 #ifdef CONFIG_PMAC_PBOOK
+#include <asm/prom.h>
 #include <asm/adb.h>
 #include <asm/pmu.h>
+#include <asm/feature.h>
 #endif
 
 
@@ -540,6 +543,14 @@
 			urb_priv_t  * urb_priv = urb->hcpriv;
 			urb_priv->state = URB_DEL; 
 
+			/* we need to do this *before* we can possibly
+			 * get the interrupt which will wake us up. */
+			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
+			    && !in_interrupt() && !ohci->disabled) {
+				add_wait_queue (&op_wakeup, &wait);
+				current->state = TASK_UNINTERRUPTIBLE;
+			}
+
 			/* we want to delete the TDs of an URB from an ed 
 			 * request the deletion, it will be handled at the
 			 * next USB-frame */
@@ -549,13 +560,34 @@
 			urb_priv->ed->state |= ED_URB_DEL;
 			spin_unlock_irqrestore (&usb_ed_lock, flags);
 			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
-				usb_dec_dev_use (urb->dev);	
-				add_wait_queue (&op_wakeup, &wait);
-				current->state = TASK_UNINTERRUPTIBLE;
-				if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
-					err("unlink URB timeout!");
-				remove_wait_queue (&op_wakeup, &wait); 
-				urb->status = -ENOENT;
+				if (ohci->disabled) {
+					/* Need to handle that case */
+				} else if (in_interrupt()) {
+					volatile u16* frame_p = (volatile u16*)&ohci->hcca.frame_no;
+					u16 frame_prev, frame, count;
+					count = 0;
+					writel (OHCI_INTR_SF, &ohci->regs->intrdisable);
+					frame_prev = le16_to_cpu(*frame_p) & 1;
+					do {
+						mb();
+						frame = le16_to_cpu(*frame_p) & 1;
+						if (frame != frame_prev) {
+							if (ohci->ed_rm_list[!frame] != NULL)
+								dl_del_list (ohci, !frame);
+							frame_prev = frame;
+							count++;
+						}			
+					} while(count < 2);
+					writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+					urb->status = -ENOENT;
+					usb_dec_dev_use (urb->dev);
+				} else {
+					if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+						err("unlink URB timeout!");
+					remove_wait_queue (&op_wakeup, &wait); 
+					urb->status = -ENOENT;
+					usb_dec_dev_use (urb->dev);	
+				}
 			} else {
 				/* usb_dec_dev_use done in dl_del_list() */
 				urb->status = -EINPROGRESS;
@@ -718,10 +750,11 @@
 	volatile ed_t * ed = edi;
 	
 	ed->state = ED_OPER;
+	ed->hwNextED = 0;
+	wmb();
 	
 	switch (ed->type) {
 	case CTRL:
-		ed->hwNextED = 0;
 		if (ohci->ed_controltail == NULL) {
 			writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
 		} else {
@@ -732,7 +765,6 @@
 		break;
 		
 	case BULK:  
-		ed->hwNextED = 0;
 		if (ohci->ed_bulktail == NULL) {
 			writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
 		} else {
@@ -748,7 +780,7 @@
 		ed->int_interval = interval;
 		int_branch = ep_int_ballance (ohci, interval, load);
 		ed->int_branch = int_branch;
-		
+
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
 			inter = 1;
 			for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); 
@@ -756,6 +788,7 @@
 				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
 					inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
 			ed->hwNextED = *ed_p; 
+			wmb();
 			*ed_p = cpu_to_le32 (virt_to_bus (ed));
 		}
 #ifdef DEBUG
@@ -764,7 +797,6 @@
 		break;
 		
 	case ISO:
-		ed->hwNextED = 0;
 		ed->int_interval = 1;
 		if (ohci->ed_isotail != NULL) {
 			ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
@@ -774,7 +806,7 @@
 				inter = 1;
 				for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
 					*ed_p != 0; 
-					ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
+					ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED))
 						inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
 				*ed_p = cpu_to_le32 (virt_to_bus (ed));	
 			}	
@@ -1005,6 +1037,7 @@
 	td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
 	td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
 	td_pt->hwNextTD = 0;
+	wmb();
 	td->ed->hwTailP = td->hwNextTD;
    
 	td->next_dl_td = NULL; //td_pt;
@@ -1047,6 +1080,7 @@
 				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
 			td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
 			cnt++;
+			wmb();
 			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
 			break;
 
@@ -1067,6 +1101,7 @@
 			info = usb_pipeout (urb->pipe)? 
  				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
 			td_fill (info, NULL, 0, urb, cnt++);
+			wmb();
 			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
 			break;
 
@@ -1808,7 +1843,8 @@
 	}
   
 	if (ints & OHCI_INTR_WDH) {
-		writel (OHCI_INTR_WDH, &regs->intrdisable);	
+		writel (OHCI_INTR_WDH, &regs->intrdisable);
+		(void)readl(&regs->intrdisable); // PCI write posting will hurt you
 		dl_done_list (ohci, dl_reverse_done_list (ohci));
 		writel (OHCI_INTR_WDH, &regs->intrenable); 
 	}
@@ -1821,6 +1857,7 @@
 	if (ints & OHCI_INTR_SF) { 
 		unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
 		writel (OHCI_INTR_SF, &regs->intrdisable);	
+		(void)readl(&regs->intrdisable); // PCI write posting will hurt you
 		if (ohci->ed_rm_list[!frame] != NULL) {
 			dl_del_list (ohci, !frame);
 		}
@@ -1932,6 +1969,7 @@
 	if (!ohci) {
 		return -ENOMEM;
 	}
+	ohci->pci_dev = dev;
 
 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
 	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
@@ -2004,19 +2042,43 @@
 {
 	struct list_head * ohci_l;
 	ohci_t * ohci;
-       
-	for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-	ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-
+   
+	for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list;
+	     ohci_l = ohci_l->next) {
+		struct device_node* node;
+		ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
+		node = find_pci_device_OFnode(ohci->pci_dev->bus->number,
+					      ohci->pci_dev->devfn);
 		switch (when) {
 		case PBOOK_SLEEP_NOW:
+			/* We should make sure processing of current frames have
+			 * finished and WDH has been porcessed
+			 */
+			dbg("USB suspend: %p", ohci->regs);
 			disable_irq (ohci->irq);
-			writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control);
-			wait_ms (10);
+
+			ohci->hc_control &= ~(OHCI_CTRL_CLE | OHCI_CTRL_BLE | OHCI_CTRL_PLE | OHCI_CTRL_IE);
+			writel (ohci->hc_control, &ohci->regs->control); 
+			writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+			(void)readl(&ohci->regs->intrstatus);
+			mdelay(2);
+
+			ohci->hc_control = OHCI_USB_SUSPEND;
+			writel (ohci->hc_control, &ohci->regs->control);
+			mdelay (10);
+			ohci->disabled = 1;
+			if (node)
+				feature_set_usb_power(node, 0);
 			break;
 		case PBOOK_WAKE:
- 			writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
-			wait_ms (20);
+			/* did we suspend, or were we powered off? */
+			if (node)
+				feature_set_usb_power(node, 1);
+			mdelay(100);
+			ohci->disabled = 0;
+			ohci->hc_control = OHCI_USB_RESUME;
+			writel (ohci->hc_control, &ohci->regs->control);
+			mdelay (35);
 			ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
 			writel (ohci->hc_control, &ohci->regs->control);
 			enable_irq (ohci->irq);
@@ -2027,7 +2089,7 @@
 }
 
 static struct pmu_sleep_notifier ohci_sleep_notifier = {
-       ohci_sleep_notify, SLEEP_LEVEL_MISC,
+       ohci_sleep_notify, SLEEP_LEVEL_USB,
 };
 #endif /* CONFIG_PMAC_PBOOK */
 
@@ -2096,11 +2158,11 @@
 {
 	int ret = -ENODEV;
 	struct pci_dev * dev = NULL;
- 
+
 	while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) { 
 		if (hc_start_ohci(dev) >= 0) ret = 0;
 	}
-    
+
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_register_sleep_notifier (&ohci_sleep_notifier);
 #endif  
diff -urN linux-2.2.18-pre20/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h
--- linux-2.2.18-pre20/drivers/usb/usb-ohci.h	Mon Dec  3 22:14:09 2001
+++ linux/drivers/usb/usb-ohci.h	Mon Dec  3 22:14:18 2001
@@ -410,6 +410,7 @@
 	struct usb_bus * bus;    
 	struct usb_device * dev[128];
 	struct virt_root_hub rh;
+	struct pci_dev *pci_dev;
 } ohci_t;
 
 
diff -urN linux-2.2.18-pre20/drivers/video/aty128.h linux/drivers/video/aty128.h
--- linux-2.2.18-pre20/drivers/video/aty128.h	Mon Sep  4 10:39:22 2000
+++ linux/drivers/video/aty128.h	Mon Dec  3 22:14:18 2001
@@ -43,10 +43,12 @@
 #define OVR_CLR					0x0230
 #define OVR_WID_LEFT_RIGHT			0x0234
 #define OVR_WID_TOP_BOTTOM			0x0238
+#define LVDS_GEN_CNTL				0x02d0
 #define DDA_CONFIG				0x02e0
 #define DDA_ON_OFF				0x02e4
 #define VGA_DDA_CONFIG				0x02e8
 #define VGA_DDA_ON_OFF				0x02ec
+#define CRTC2_GEN_CNTL				0x03f8
 #define OV0_SCALE_CNTL				0x0420
 #define SUBPIC_CNTL				0x0540
 #define PM4_BUFFER_OFFSET			0x0700
@@ -218,6 +220,7 @@
 
 #define PLL_WR_EN				0x00000080
 
+/* PLL registers */
 #define CLK_PIN_CNTL				0x0001
 #define PPLL_CNTL				0x0002
 #define PPLL_REF_DIV				0x0003
@@ -236,6 +239,7 @@
 #define AGP_PLL_CNTL				0x0010
 #define FCP_CNTL				0x0012
 #define PLL_TEST_CNTL				0x0013
+#define POWER_MANAGEMENT			0x002f
 
 #define PPLL_RESET				0x01
 #define PPLL_ATOMIC_UPDATE_EN			0x10000
@@ -266,7 +270,8 @@
 #define DAC_MASK				0xFF000000
 #define DAC_BLANKING				0x00000004
 #define DAC_RANGE_CNTL				0x00000003
-#define PALETTE_ACCESS_CNTL			0x00000020
+#define DAC_PALETTE_ACCESS_CNTL			0x00000020
+#define DAC_PDWN				0x00008000
 
 /* GEN_RESET_CNTL bit constants */
 #define SOFT_RESET_GUI				0x00000001
@@ -338,5 +343,43 @@
 #define DP_SRC_RECT				0x00000200
 #define DP_SRC_HOST				0x00000300
 #define DP_SRC_HOST_BYTEALIGN			0x00000400
+
+/* LVDS_GEN_CNTL constants */
+#define LVDS_BL_MOD_LEVEL_MASK			0x0000ff00
+#define LVDS_BL_MOD_LEVEL_SHIFT			8
+#define LVDS_BL_MOD_EN				0x00010000
+#define LVDS_DIGION				0x00040000
+#define LVDS_BLON				0x00080000
+#define LVDS_ON					0x00000001
+#define LVDS_DISPLAY_DIS			0x00000002
+#define LVDS_PANEL_TYPE_2PIX_PER_CLK		0x00000004
+#define LVDS_PANEL_24BITS_TFT			0x00000008
+#define LVDS_FRAME_MOD_NO			0x00000000
+#define LVDS_FRAME_MOD_2_LEVELS			0x00000010
+#define LVDS_FRAME_MOD_4_LEVELS			0x00000020
+#define LVDS_EN					0x00000080
+
+/* CRTC2_GEN_CNTL constants */
+#define CRTC2_EN				0x02000000
+
+/* POWER_MANAGEMENT constants */
+#define	PWR_MGT_ON				0x00000001
+#define PWR_MGT_MODE_MASK			0x00000006
+#define PWR_MGT_MODE_PIN			0x00000000
+#define PWR_MGT_MODE_REGISTER			0x00000002
+#define PWR_MGT_MODE_TIMER			0x00000004
+#define PWR_MGT_MODE_PCI			0x00000006
+#define PWR_MGT_AUTO_PWR_UP_EN			0x00000008
+#define PWR_MGT_ACTIVITY_PIN_ON			0x00000010
+#define PWR_MGT_STANDBY_POL			0x00000020
+#define PWR_MGT_SUSPEND_POL			0x00000040
+#define PWR_MGT_SELF_REFRESH			0x00000080
+#define PWR_MGT_ACTIVITY_PIN_EN			0x00000100
+#define PWR_MGT_KEYBD_SNOOP			0x00000200
+#define PWR_MGT_TRISTATE_MEM_EN			0x00000800
+#define PWR_MGT_SELW4MS				0x00001000
+#define PWR_MGT_SLOWDOWN_MCLK			0x00002000
+
+#define PMI_PMSCR_REG				0x60
 
 #endif /* REG_RAGE128_H */
diff -urN linux-2.2.18-pre20/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- linux-2.2.18-pre20/drivers/video/aty128fb.c	Mon Dec  3 22:14:09 2001
+++ linux/drivers/video/aty128fb.c	Mon Dec  3 22:14:18 2001
@@ -50,6 +50,9 @@
 #include <asm/pci-bridge.h>
 #include <linux/nvram.h>
 #include <video/macmodes.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#include <asm/backlight.h>
 #endif
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
@@ -261,6 +264,9 @@
     struct display disp;
     struct display_switch dispsw;       /* for cursor and font */
     struct { u8 red, green, blue, pad; } palette[256];
+#ifdef CONFIG_PMAC_PBOOK
+    unsigned char *save_framebuffer;
+#endif
     union {
 #ifdef FBCON_HAS_CFB16
     u16 cfb16[16];
@@ -284,6 +290,15 @@
 
 static struct fb_info_aty128 *board_list = NULL;
 
+#ifdef CONFIG_PMAC_PBOOK
+  int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when);
+  static struct pmu_sleep_notifier aty128_sleep_notifier = {
+  	aty128_sleep_notify, SLEEP_LEVEL_VIDEO,
+  };
+#endif
+
+
+
 #define round_div(n, d) ((n+(d/2))/d)
 
     /*
@@ -349,7 +364,9 @@
                              const struct fb_info_aty128 *info);
 static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128
 				*board_list, struct fb_info_aty128 *new_node);
+#ifndef CONFIG_FB_OF
 static int aty128find_ROM(struct fb_info_aty128 *info);
+#endif
 #ifndef CONFIG_PPC
 static void aty128_get_pllinfo(struct fb_info_aty128 *info);
 #endif
@@ -402,6 +419,15 @@
     aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl
 };
 
+#ifdef CONFIG_PPC
+static int aty128_set_backlight_enable(int on, int level, void* data);
+static int aty128_set_backlight_level(int level, void* data);
+
+static struct backlight_controller aty128_backlight_controller = {
+	aty128_set_backlight_enable,
+	aty128_set_backlight_level
+};
+#endif
 
     /*
      * Functions to read from/write to the mmio registers
@@ -1725,17 +1751,20 @@
 #else
     memset(&var, 0, sizeof(var));
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_FB_OF
     if (default_vmode == VMODE_CHOOSE) {
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_FB_OF */
         var = default_var;
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_FB_OF
+	/* New iBook */
+	if (machine_is_compatible("PowerBook2,2"))
+		default_vmode = VMODE_800_600_60;
     } else {
 	if (mac_vmode_to_var(default_vmode, default_cmode, &var))
 	    var = default_var;
     }
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_FB_OF */
 
 #endif /* MODULE */
 
@@ -1774,6 +1803,14 @@
     if (register_framebuffer(&info->fb_info) < 0)
 	return 0;
 
+#ifdef CONFIG_PPC
+    if (info->chip_gen == rage_M3)
+    	register_backlight_controller(&aty128_backlight_controller, info, "ati");
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+    pmu_register_sleep_notifier(&aty128_sleep_notifier);
+#endif
+
     printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
 	   GET_FB_IDX(info->fb_info.node), aty128fb_name, name);
 
@@ -1905,6 +1942,7 @@
 }
 #endif /* ! CONFIG_FB_OF */
 
+#ifndef CONFIG_FB_OF
 static int __init
 aty128find_ROM(struct fb_info_aty128 *info)
 {
@@ -1970,6 +2008,7 @@
 #endif /* !CONFIG_PPC */
     return (flag);
 }
+#endif /* CONFIG_FB_OF */
 
 #ifndef CONFIG_PPC
 static void __init
@@ -2051,13 +2090,10 @@
     u8 bus, devfn;
     u16 cmd;
 
-    if (device_is_compatible(dp, "ATY,RageM3p")) {
-	/* XXX kludge for now */
-	if (dp->name == 0 || strcmp(dp->name, "ATY,RageM3pA") != 0
-	    || dp->parent == 0)
-	    return;
-	dp = dp->parent;
-    }
+    if (dp->name && !strcmp(dp->name, "ATY,RageM3pA") && dp->parent)
+    	dp = dp->parent;
+    if (dp->name && !strcmp(dp->name, "ATY,RageM3pB"))
+    	return;
 
     switch (dp->n_addrs) {
     case 3:
@@ -2230,6 +2266,11 @@
     struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
     u8 state = 0;
 
+#if defined(CONFIG_PPC)
+    if ((_machine == _MACH_Pmac) && blank)
+    	set_backlight_enable(0);
+#endif
+
     if (blank & VESA_VSYNC_SUSPEND)
 	state |= 2;
     if (blank & VESA_HSYNC_SUSPEND)
@@ -2238,6 +2279,11 @@
 	state |= 4;
 
     aty_st_8(CRTC_EXT_CNTL+1, state);
+
+#if defined(CONFIG_PPC)
+    if ((_machine == _MACH_Pmac) && !blank)
+    	set_backlight_enable(1);
+#endif
 }
 
 
@@ -2294,7 +2340,7 @@
         int i;
 
         if (info->chip_gen == rage_M3)
-            aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL);
+            aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
 
         for (i=16; i<256; i++) {
             aty_st_8(PALETTE_INDEX, i);
@@ -2303,7 +2349,7 @@
         }
 
         if (info->chip_gen == rage_M3) {
-            aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL);
+            aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
 
             for (i=16; i<256; i++) {
                 aty_st_8(PALETTE_INDEX, i);
@@ -2316,7 +2362,7 @@
     /* initialize palette */
 
     if (info->chip_gen == rage_M3)
-        aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL);
+        aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
 
     if (info->current_par.crtc.bpp == 16)
         aty_st_8(PALETTE_INDEX, (regno << 3));
@@ -2325,7 +2371,7 @@
     col = (red << 16) | (green << 8) | blue;
     aty_st_le32(PALETTE_DATA, col);
     if (info->chip_gen == rage_M3) {
-    	aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL);
+    	aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
         if (info->current_par.crtc.bpp == 16)
             aty_st_8(PALETTE_INDEX, (regno << 3));
         else
@@ -2375,6 +2421,42 @@
     }
 }
 
+#ifdef CONFIG_PPC
+
+static int backlight_conv[] = {
+	0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+	0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+
+static int
+aty128_set_backlight_enable(int on, int level, void* data)
+{
+	struct fb_info_aty128 *info = (struct fb_info_aty128 *)data;
+	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+
+	reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+	if (on && level > BACKLIGHT_OFF) {
+		reg |= LVDS_ON | LVDS_EN;
+		reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
+	} else {
+		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
+		reg &= ~(LVDS_ON | LVDS_EN);
+	}
+	aty_st_le32(LVDS_GEN_CNTL, reg);
+
+	return 0;
+}
+
+static int
+aty128_set_backlight_level(int level, void* data)
+{
+	return aty128_set_backlight_enable(1, level, data);
+}
+
+#endif
 
     /*
      *  Accelerated functions
@@ -2407,9 +2489,118 @@
     wait_for_fifo(2, info);
     aty_st_le32(DP_DATATYPE, save_dp_datatype);
     aty_st_le32(DP_CNTL, save_dp_cntl); 
+}
 
-    wait_for_idle(info);
+
+#ifdef CONFIG_PMAC_PBOOK
+
+static void
+aty128_set_suspend(struct fb_info_aty128 *info, int suspend)
+{
+	u32	pmgt;
+	
+	/* Set the chip into the appropriate suspend mode (we use D2,
+	 * D3 would require a complete re-initialisation of the chip,
+	 * including PCI config registers, clocks, AGP configuration, ...)
+	 */
+	if (suspend) {
+		/* Set the power management mode to be PCI based */
+		pmgt = aty_ld_pll(POWER_MANAGEMENT);
+		pmgt &= ~PWR_MGT_MODE_MASK;
+		pmgt |= PWR_MGT_MODE_PCI | PWR_MGT_ON | PWR_MGT_AUTO_PWR_UP_EN;
+		aty_st_pll(POWER_MANAGEMENT, pmgt);
+
+		/* Switch PCI power management to D2 */
+		pci_write_config_word(info->pdev, 0x60, 2);
+		//mdelay(10);
+	} else {
+		/* Switch back PCI power management to D0 */
+		mdelay(100);
+		pci_write_config_word(info->pdev, 0x60, 0);
+		mdelay(100);
+		//aty128_set_backlight_enable(1,10,info);
+
+	}
+}
+
+/*
+ * Save the contents of the frame buffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+int
+aty128_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	struct fb_info_aty128 *info;
+ 	int result;
+
+	result = PBOOK_SLEEP_OK;
+
+	for (info = board_list; info != NULL; info = info->next) {
+		struct fb_fix_screeninfo fix;
+		int nb;
+
+		aty128fb_get_fix(&fix, fg_console, (struct fb_info *)info);
+		nb = fb_display[fg_console].var.yres * fix.line_length;
+
+		switch (when) {
+		case PBOOK_SLEEP_REQUEST:
+			if (!info->pdev)
+				return PBOOK_SLEEP_REFUSE;
+			if (info->chip_gen != rage_M3)
+				return PBOOK_SLEEP_REFUSE;
+			info->save_framebuffer = vmalloc(nb);
+			if (info->save_framebuffer == NULL)
+				return PBOOK_SLEEP_REFUSE;
+			break;
+		case PBOOK_SLEEP_REJECT:
+			if (info->save_framebuffer) {
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+			break;
+		case PBOOK_SLEEP_NOW:
+			wait_for_idle(info);
+			aty128_reset_engine(info);
+			wait_for_idle(info);
+
+			/* Backup fb content */	
+			if (info->save_framebuffer)
+				memcpy_fromio(info->save_framebuffer,
+				       (void *)info->frame_buffer, nb);
+
+			/* Blank display and LCD */
+			aty128fbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+			
+			/* Sleep the chip */
+			aty128_set_suspend(info, 1);
+
+			break;
+		case PBOOK_WAKE:
+			/* Wake the chip */
+			aty128_set_suspend(info, 0);
+			
+			/* Test */
+			aty128fbcon_blank(0, (struct fb_info *)info);
+
+			aty128_reset_engine(info);
+			wait_for_idle(info);
+
+			/* Restore fb content */			
+			if (info->save_framebuffer) {
+				memcpy_toio((void *)info->frame_buffer,
+				       info->save_framebuffer, nb);
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+			/* Restore display */
+			aty128_set_par(&info->current_par, info);
+			aty128fbcon_blank(0, (struct fb_info *)info);
+			break;
+		}
+	}
+	return result;
 }
+#endif /* CONFIG_PMAC_PBOOK */
 
 
     /*
diff -urN linux-2.2.18-pre20/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- linux-2.2.18-pre20/drivers/video/atyfb.c	Mon Dec  3 22:14:09 2001
+++ linux/drivers/video/atyfb.c	Mon Dec  3 22:14:18 2001
@@ -70,6 +70,7 @@
 #include <video/macmodes.h>
 #include <asm/adb.h>
 #include <asm/pmu.h>
+#include <asm/backlight.h>
 #endif
 #ifdef __sparc__
 #include <asm/pbm.h>
@@ -235,7 +236,6 @@
 #endif
 #ifdef CONFIG_PMAC_PBOOK
     unsigned char *save_framebuffer;
-    unsigned long save_pll[64];
     struct fb_info_aty* next;
 #endif
 };
@@ -412,6 +412,16 @@
 #endif
 };
 
+#ifdef CONFIG_PPC
+static int aty_set_backlight_enable(int on, int level, void* data);
+static int aty_set_backlight_level(int level, void* data);
+
+static struct backlight_controller aty_backlight_controller = {
+	aty_set_backlight_enable,
+	aty_set_backlight_level
+};
+#endif
+
 static char atyfb_name[16] = "ATY Mach64";
 static char fontname[40] __initdata = { 0 };
 static char curblink __initdata = 1;
@@ -2783,6 +2793,8 @@
 	aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info)
 		| (USE_F32KHZ | TRISTATE_MEM_EN), info);
     }
+    if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID))
+	register_backlight_controller(&aty_backlight_controller, info, "ati");
 
     if (default_vmode == VMODE_NVRAM) {
 #if 0 /* This is not really supported */
@@ -3494,7 +3506,7 @@
 
 #if defined(CONFIG_PPC)
     if ((_machine == _MACH_Pmac) && blank)
-    	pmu_enable_backlight(0);
+    	set_backlight_enable(0);
 #endif
 
     gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
@@ -3519,7 +3531,7 @@
 
 #if defined(CONFIG_PPC)
     if ((_machine == _MACH_Pmac) && !blank)
-    	pmu_enable_backlight(1);
+    	set_backlight_enable(1);
 #endif
 }
 
@@ -4215,6 +4227,38 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
+#ifdef CONFIG_PPC
+static int backlight_conv[] = {
+	0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
+	0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
+};
+
+static int
+aty_set_backlight_enable(int on, int level, void* data)
+{
+	struct fb_info_aty *info = (struct fb_info_aty *)data;
+	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info);
+	
+	reg |= (BLMOD_EN | BIASMOD_EN);
+	if (on && level > BACKLIGHT_OFF) {
+		reg &= ~BIAS_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+	} else {
+		reg &= ~BIAS_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+	}
+	aty_st_lcd(LCD_MISC_CNTL, reg, info);
+	return 0;
+}
+
+static int
+aty_set_backlight_level(int level, void* data)
+{
+	return aty_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PPC */
+
+ 
 #ifdef MODULE
 
 int blink = 1;
@@ -4222,7 +4266,7 @@
 static int pll = 0;
 static int mclk = 0;
 #if defined(CONFIG_PPC)
-static int vmode = VMODE_NVRAM;
+static int vmode = VMODE_CHOOSE;
 static int cmode = CMODE_NVRAM;
 #endif
 
diff -urN linux-2.2.18-pre20/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- linux-2.2.18-pre20/drivers/video/chipsfb.c	Mon Sep  4 10:39:22 2000
+++ linux/drivers/video/chipsfb.c	Mon Dec  3 22:14:18 2001
@@ -37,6 +37,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/adb.h>
 #include <asm/pmu.h>
+#include <asm/backlight.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -281,7 +282,7 @@
 	// used to disable backlight only for blank > 1, but it seems
 	// useful at blank = 1 too (saves battery, extends backlight life)
 	if (blank) {
-		pmu_enable_backlight(0);
+		set_backlight_enable(0);
 		/* get the palette from the chip */
 		for (i = 0; i < 256; ++i) {
 			out_8(p->io_base + 0x3c7, i);
@@ -298,7 +299,7 @@
 			out_8(p->io_base + 0x3c9, 0);
 		}
 	} else {
-		pmu_enable_backlight(1);
+		set_backlight_enable(1);
 		for (i = 0; i < 256; ++i) {
 			out_8(p->io_base + 0x3c8, i);
 			udelay(1);
@@ -417,7 +418,7 @@
 	disp->visual = fix->visual;
 	disp->var = *var;
 
-#if (defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_FB_COMPAT_XPMAC))
+#ifdef CONFIG_FB_COMPAT_XPMAC
 	display_info.depth = bpp;
 	display_info.pitch = fix->line_length;
 #endif
@@ -707,7 +708,7 @@
 	memset(p->frame_buffer, 0, 0x100000);
 
 	/* turn on the backlight */
-	pmu_enable_backlight(1);
+	set_backlight_enable(1);
 
 	init_chips(p);
 }
diff -urN linux-2.2.18-pre20/drivers/video/offb.c linux/drivers/video/offb.c
--- linux-2.2.18-pre20/drivers/video/offb.c	Mon Sep  4 10:39:22 2000
+++ linux/drivers/video/offb.c	Mon Dec  3 22:14:18 2001
@@ -48,7 +48,8 @@
 	cmap_m64,	/* ATI Mach64 */
 	cmap_r128,	/* ATI Rage128 */
 	cmap_M3A,	/* ATI Rage Mobility M3 Head A */
-	cmap_M3B	/* ATI Rage Mobility M3 Head B */
+	cmap_M3B,	/* ATI Rage Mobility M3 Head B */
+	cmap_radeon	/* ATI Radeon */
 };
 
 struct fb_info_offb {
@@ -347,6 +348,10 @@
 	/* find the device node corresponding to the macos display */
 	for (dp = displays; dp != NULL; dp = dp->next) {
 	    int i;
+	    
+	    if (!strcmp(dp->name, "offscreen-display"))
+	    	continue;
+	    
 	    /*
 	     * Grrr...  It looks like the MacOS ATI driver
 	     * munges the assigned-addresses property (but
@@ -426,6 +431,8 @@
 
     if (!ofonly) {
 	for (dp = find_type_devices("display"); dp != NULL; dp = dp->next) {
+	    if (!strcmp(dp->name, "offscreen-display"))
+	    	continue;
 	    for (dpy = 0; dpy < prom_num_displays; dpy++)
 		if (strcmp(dp->full_name, prom_display_paths[dpy]) == 0)
 		    break;
@@ -439,12 +446,13 @@
 {
 #ifdef CONFIG_FB_ATY128
     if (!strncmp(dp->name, "ATY,Rage128", 11) ||
+    	!strncmp(dp->name, "ATY,RageM3p1", 12) ||
     	!strncmp(dp->name, "ATY,RageM3pA", 12)) {
 	aty128fb_of_init(dp);
 	return 1;
     }
     if (!strncmp(dp->name, "ATY,RageM3pB", 12))
-    	return 0;
+    	return 1;
 #endif /* CONFIG_FB_ATY128*/
 #ifdef CONFIG_FB_ATY
     if (!strncmp(dp->name, "ATY", 3)) {
@@ -591,7 +599,8 @@
 		unsigned long regbase = dp->addrs[2].address;
 		info->cmap_adr = ioremap(regbase, 0x1FFF);
 		info->cmap_type = cmap_r128;
-	} else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) {
+	} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) ||
+		!strncmp(name, "ATY,RageM3p1", 12))) {
 		unsigned long regbase = dp->parent->addrs[2].address;
 		info->cmap_adr = ioremap(regbase, 0x1FFF);
 		info->cmap_type = cmap_M3A;
@@ -599,6 +608,10 @@
 		unsigned long regbase = dp->parent->addrs[2].address;
 		info->cmap_adr = ioremap(regbase, 0x1FFF);
 		info->cmap_type = cmap_M3B;
+	} else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
+		unsigned long regbase = dp->addrs[1].address;
+		info->cmap_adr = ioremap(regbase, 0x1FFF);
+		info->cmap_type = cmap_radeon;
 	} else if (!strncmp(name, "ATY,", 4)) {
 		unsigned long base = address & 0xff000000UL;
 		info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
@@ -848,6 +861,10 @@
 	    	out_8(info2->cmap_adr + 0xb0, i);
 	    	out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
 	    	break;
+	    case cmap_radeon:
+    	        out_8(info2->cmap_adr + 0xb0, i);
+	    	out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
+	    	break;
 	    }
 	}
     else
@@ -928,6 +945,12 @@
   	out_le32((unsigned *)(info2->cmap_adr + 0xb4),
     		(red << 16 | green << 8 | blue));
     	break;
+    case cmap_radeon:
+	/* Set palette index & data (could be smarter) */
+	out_8(info2->cmap_adr + 0xb0, regno);
+  	out_le32((unsigned *)(info2->cmap_adr + 0xb4),
+    		(red << 16 | green << 8 | blue));
+	break;
     }
 
     if (regno < 16)
diff -urN linux-2.2.18-pre20/fs/Config.in linux/fs/Config.in
--- linux-2.2.18-pre20/fs/Config.in	Mon Dec  3 22:14:09 2001
+++ linux/fs/Config.in	Mon Dec  3 22:14:18 2001
@@ -78,6 +78,7 @@
   tristate 'NFS server support' CONFIG_NFSD
   if [ "$CONFIG_NFSD" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
     bool '   NFS Version 3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
+    bool '   NFS server TCP support (VERY EXPERIMENTAL)' CONFIG_NFSD_TCP
   fi
   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
     define_bool CONFIG_SUNRPC y
diff -urN linux-2.2.18-pre20/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- linux-2.2.18-pre20/fs/nfsd/nfssvc.c	Mon Dec  3 22:14:09 2001
+++ linux/fs/nfsd/nfssvc.c	Mon Dec  3 22:14:18 2001
@@ -76,9 +76,11 @@
 	if (error < 0)
 		goto failure;
 
+#ifdef CONFIG_NFSD_TCP
 	error = svc_makesock(serv, IPPROTO_TCP, port);
 	if (error < 0)
 		goto failure;
+#endif
 
 	nfsd_racache_init();	/* Readahead param cache */
 
diff -urN linux-2.2.18-pre20/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.2.18-pre20/fs/proc/array.c	Mon Sep  4 10:39:27 2000
+++ linux/fs/proc/array.c	Mon Dec  3 22:14:18 2001
@@ -295,8 +295,8 @@
                 "swap %u %u\n"
 		"intr 1 0",   
 #else                             
-		"swap %u %u\n"
-		"intr %u",
+                "swap %u %u\n"    
+                "intr %u",        
 #endif                            
 		kstat.cpu_user,
 		kstat.cpu_nice,
@@ -319,7 +319,7 @@
 #ifdef CONFIG_ARCH_S390
 		kstat.pswpout);
 #else
-		kstat.pswpout,
+                kstat.pswpout, 
 		sum);
 	for (i = 0 ; i < NR_IRQS ; i++)
 		len += sprintf(buffer + len, " %u", kstat_irqs(i));
@@ -911,9 +911,6 @@
 {
 	char * orig = buffer;
 	struct task_struct *tsk;
-#if  __s390__
-	int line,len;
-#endif
 
 	read_lock(&tasklist_lock);
 	tsk = find_task_by_pid(pid);
@@ -926,8 +923,7 @@
 	buffer = task_sig(tsk, buffer);
 	buffer = task_cap(tsk, buffer);
 #if __s390__
-	for(line=0;(len=sprintf_regs(line,buffer,tsk,NULL,NULL))!=0;line++)
-		buffer+=len;
+	buffer = task_show_regs(tsk, buffer);
 #endif
 	return buffer - orig;
 }
diff -urN linux-2.2.18-pre20/include/asm-ppc/backlight.h linux/include/asm-ppc/backlight.h
--- linux-2.2.18-pre20/include/asm-ppc/backlight.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/backlight.h	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,28 @@
+/*
+ * Routines for handling backlight control on PowerBooks
+ * 
+ * For now, implementation resides in arch/ppc/kernel/pmac_support.c
+ * 
+ */
+#ifndef __ASM_PPC_BACKLIGHT_H
+#define __ASM_PPC_BACKLIGHT_H
+
+/* Abstract values */
+#define BACKLIGHT_OFF	0
+#define BACKLIGHT_MIN	1
+#define BACKLIGHT_MAX	0xf
+
+struct backlight_controller {
+	int (*set_enable)(int enable, int level, void *data);
+	int (*set_level)(int level, void *data);
+};
+
+extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type);
+extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data);
+
+extern int set_backlight_enable(int enable);
+extern int get_backlight_enable(void);
+extern int set_backlight_level(int level);
+extern int get_backlight_level(void);
+
+#endif
diff -urN linux-2.2.18-pre20/include/asm-ppc/delay.h linux/include/asm-ppc/delay.h
--- linux-2.2.18-pre20/include/asm-ppc/delay.h	Mon Dec  3 22:14:09 2001
+++ linux/include/asm-ppc/delay.h	Mon Dec  3 22:14:18 2001
@@ -12,6 +12,11 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+extern unsigned long loops_per_jiffy;
+
+/* maximum permitted argument to udelay */
+#define __MAX_UDELAY	1000000
+
 extern __inline__ void __delay(unsigned int loops)
 {
 	if (loops != 0)
@@ -19,15 +24,30 @@
 				     "r" (loops) : "ctr");
 }
 
-extern __inline__ void udelay(unsigned long usecs)
+/* N.B. the `secs' parameter here is a fixed-point number with
+   the binary point to the left of the most-significant bit. */
+extern __inline__ void __const_udelay(unsigned int secs)
 {
-	unsigned long loops;
+	unsigned int loops;
 
-	/* compute (usecs * 2^32 / 10^6) * (loops_per_jiffy*HZ) / 2^32 */
-	usecs *= 0x10c6;		/* 2^32 / 10^6 */
 	__asm__("mulhwu %0,%1,%2" : "=r" (loops) :
-		"r" (usecs), "r" (loops_per_jiffy*HZ));
-	__delay(loops);
+		"r" (secs), "r" (loops_per_jiffy));
+	__delay(loops * HZ);
 }
+
+/*
+ * note that 4294 == 2^32 / 10^6, multiplying by 4294 converts from
+ * microseconds to a 32-bit fixed-point number of seconds.
+ */
+extern __inline__ void __udelay(unsigned int usecs)
+{
+	__const_udelay(usecs * 4294);
+}
+
+extern void __bad_udelay(void);		/* deliberately undefined */
+
+#define udelay(n) (__builtin_constant_p(n)? \
+		   ((n) > __MAX_UDELAY? __bad_udelay(): __const_udelay((n) * 4294u)) : \
+		   __udelay(n))
 
 #endif /* defined(_PPC_DELAY_H) */
diff -urN linux-2.2.18-pre20/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- linux-2.2.18-pre20/include/asm-ppc/dma.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/dma.h	Mon Dec  3 22:14:18 2001
@@ -203,6 +203,7 @@
 	 */
 	unsigned char ucDmaCmd=0x00;
 
+#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
 	if(_prep_type==_PREP_Radstone)
 	{
 		switch(ucSystemType)
@@ -227,6 +228,7 @@
 			}
 		}
 	}
+#endif /* CONFIG_PREP || CONFIG_ALL_PPC */
 
 	if (dmanr != 4)
 	{
diff -urN linux-2.2.18-pre20/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h
--- linux-2.2.18-pre20/include/asm-ppc/feature.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/feature.h	Mon Dec  3 22:14:18 2001
@@ -45,6 +45,7 @@
 	FEATURE_IDE2_reset,
 	FEATURE_Mediabay_IDE_switch,	/* MB IDE bus switch */
 	FEATURE_Mediabay_content,	/* MB content indicator enable */
+	FEATURE_Airport_reset,		/* Is it actually a reset ? */
 	FEATURE_last,
 };
 
@@ -69,5 +70,27 @@
 /* Initialize feature stuff */
 extern void	feature_init(void);
 
+/*
+ * Additional functions related to Core99 machines
+ */
+extern void	feature_set_gmac_power(struct device_node* device, int power);
+
+	/* use constants in KeyLargo.h for the reset parameter */
+extern void	feature_set_gmac_phy_reset(struct device_node* device, int reset);
+
+extern void	feature_set_usb_power(struct device_node* device, int power);
+
+extern void 	feature_set_firewire_power(struct device_node* device, int power);
+
+extern void	feature_core99_kick_cpu1(void);
+
+/*
+ * Sleep related functions. At term, they should be high-priority notifiers,
+ * but this would require some changes to the current sleep scheme that won't
+ * be done in 2.2.
+ */
+extern void	feature_prepare_for_sleep(void);
+
+extern void	feature_wake_up(void);
 
 #endif /* __ASM_PPC_FEATURE_H */
diff -urN linux-2.2.18-pre20/include/asm-ppc/heathrow.h linux/include/asm-ppc/heathrow.h
--- linux-2.2.18-pre20/include/asm-ppc/heathrow.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/heathrow.h	Mon Dec  3 22:14:18 2001
@@ -44,4 +44,10 @@
 #define HRW_BMAC_IO_ENABLE	0x60000000	/* two bits, not documented in OF */
 #define HRW_BMAC_RESET		0x80000000	/* not documented in OF */
 
+/* We OR those features at boot on desktop G3s */
+#define HRW_DEFAULTS		(HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE)
+
+/* Those seem to be different on paddington */
 #define PADD_MODEM_POWER_N	0x00000001	/* modem power on paddington */
+#define PADD_RESET_SCC		0x02000000	/* check this please */
+
diff -urN linux-2.2.18-pre20/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- linux-2.2.18-pre20/include/asm-ppc/irq.h	Mon Aug  9 12:04:57 1999
+++ linux/include/asm-ppc/irq.h	Mon Dec  3 22:14:18 2001
@@ -31,8 +31,6 @@
 #define NUM_8259_INTERRUPTS	16
 #define NUM_OPENPIC_INTERRUPTS	20
 #define is_8259_irq(n)		((n) < NUM_8259_INTERRUPTS)
-#define openpic_to_irq(n)	((n)+NUM_8259_INTERRUPTS)
-#define irq_to_openpic(n)	((n)-NUM_8259_INTERRUPTS)
 #define IRQ_8259_CASCADE	NUM_8259_INTERRUPTS
 
 #ifndef CONFIG_APUS
diff -urN linux-2.2.18-pre20/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- linux-2.2.18-pre20/include/asm-ppc/keyboard.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/keyboard.h	Mon Dec  3 22:14:18 2001
@@ -71,8 +71,8 @@
 		ppc_md.kbd_init_hw();
 }
 
-#define kbd_sysrq_xlate	(ppc_md.kbd_sysrq_xlate)
-#define SYSRQ_KEY (ppc_md.SYSRQ_KEY)
+#define kbd_sysrq_xlate	(ppc_md.sysrq_xlate)
+extern unsigned long SYSRQ_KEY;
 
 /* resource allocation */
 #define kbd_request_region()
diff -urN linux-2.2.18-pre20/include/asm-ppc/keylargo.h linux/include/asm-ppc/keylargo.h
--- linux-2.2.18-pre20/include/asm-ppc/keylargo.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/keylargo.h	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,119 @@
+/*
+ * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
+ *
+ */
+
+/* offset from base for feature control registers */
+#define KEYLARGO_MBCR		0x34	/* Media bay control/status */
+#define KEYLARGO_FCR0		0x38
+#define KEYLARGO_FCR1		0x3c
+#define KEYLARGO_FCR2		0x40
+#define KEYLARGO_FCR3		0x44
+#define KEYLARGO_FCR4		0x48
+
+/* GPIO registers */
+#define KEYLARGO_GPIO_LEVELS0		0x50
+#define KEYLARGO_GPIO_LEVELS1		0x54
+#define KEYLARGO_GPIO_EXTINT_0		0x58
+#define KEYLARGO_GPIO_EXTINT_CNT	18
+#define KEYLARGO_GPIO_0			0x6A
+#define KEYLARGO_GPIO_CNT		17
+
+/* Specific GPIO regs */
+
+#define KL_GPIO_ETH_PHY_RESET		(KEYLARGO_GPIO_0+0x10)
+#define KL_GPIO_ETH_PHY_RESET_ASSERT	0x04
+#define KL_GPIO_ETH_PHY_RESET_RELEASE	0x05
+#define KL_GPIO_ETH_PHY_RESET_TRISTATE	0x00
+
+#define KL_GPIO_EXTINT_CPU1		(KEYLARGO_GPIO_0+0x0a)
+#define KL_GPIO_EXTINT_CPU1_ASSERT	0x04
+#define KL_GPIO_EXTINT_CPU1_RELEASE	0x38
+
+#define KL_GPIO_RESET_CPU0		(KEYLARGO_GPIO_EXTINT_0+0x03)
+#define KL_GPIO_RESET_CPU1		(KEYLARGO_GPIO_EXTINT_0+0x04)
+#define KL_GPIO_RESET_CPU2		(KEYLARGO_GPIO_EXTINT_0+0x0f)
+#define KL_GPIO_RESET_CPU3		(KEYLARGO_GPIO_EXTINT_0+0x10)
+#define KL_GPIO_RESET_CPU_ASSERT	0x04
+#define KL_GPIO_RESET_CPU_RELEASE	0x05
+
+#define KL_GPIO_PMU_MESSAGE_IRQ		(KEYLARGO_GPIO_EXTINT_0+0x09)
+#define KL_GPIO_PMU_MESSAGE_BIT		0x02
+
+/*
+ * Bits in feature control register
+ */
+#define KL_MBCR_MBDEV_ENABLE		0x00001000
+
+#define KL0_SCC_B_INTF_ENABLE		0x00000001	/* ??? */
+#define KL0_SCC_A_INTF_ENABLE		0x00000002	/* ??? */
+#define KL0_SCC_SLOWPCLK		0x00000004
+#define KL0_SCC_RESET			0x00000008
+#define KL0_SCCA_ENABLE			0x00000010
+#define KL0_SCCB_ENABLE			0x00000020
+#define KL0_SCC_CELL_ENABLE		0x00000040
+#define KL0_IRDA_ENABLE			0x00008000
+#define KL0_IRDA_CLK32_ENABLE		0x00010000
+#define KL0_IRDA_CLK19_ENABLE		0x00020000
+#define KL0_USB0_PAD_SUSPEND0		0x00040000
+#define KL0_USB0_PAD_SUSPEND1		0x00080000
+#define KL0_USB0_CELL_ENABLE		0x00100000
+#define KL0_USB1_PAD_SUSPEND0		0x00400000
+#define KL0_USB1_PAD_SUSPEND1		0x00800000
+#define KL0_USB1_CELL_ENABLE		0x01000000
+#define KL0_USB_REF_SUSPEND		0x10000000
+
+#define KL0_SERIAL_ENABLE		(KL0_SCC_B_INTF_ENABLE | \
+					KL0_SCC_SLOWPCLK | \
+					KL0_SCC_CELL_ENABLE | KL0_SCCA_ENABLE)
+
+#define KL1_AUDIO_SEL_22MCLK		0x00000002
+#define KL1_AUDIO_CLK_ENABLE_BIT	0x00000008
+#define KL1_AUDIO_CLK_OUT_ENABLE	0x00000020	/* Burgundy only ? */
+#define KL1_AUDIO_CELL_ENABLE		0x00000040
+#define KL1_AUDIO_CHOOSE		0x00000080	/* Burgundy only ? */
+#define KL1_I2S0_CELL_ENABLE		0x00000400
+#define KL1_I2S0_CLK_ENABLE_BIT		0x00001000
+#define KL1_I2S0_ENABLE			0x00002000
+#define KL1_I2S1_CELL_ENABLE		0x00020000
+#define KL1_I2S1_CLK_ENABLE_BIT		0x00080000
+#define KL1_I2S1_ENABLE			0x00100000
+#define KL1_EIDE0_ENABLE		0x00800000
+#define KL1_EIDE0_RESET_N		0x01000000
+#define KL1_EIDE1_ENABLE		0x04000000
+#define KL1_EIDE1_RESET_N		0x08000000
+#define KL1_UIDE_ENABLE			0x20000000
+#define KL1_UIDE_RESET_N		0x40000000
+
+#define KL2_IOBUS_ENABLE		0x00000002
+#define KL2_SLEEP_STATE_BIT		0x00000100
+#define KL2_MPIC_ENABLE			0x00020000
+#define KL2_MODEM_POWER_N		0x02000000
+#define KL2_AIRPORT_RESET_N		0x08000000	/* Or power ? */
+
+#define KL3_SHUTDOWN_PLL_TOTAL		0x00000001
+#define KL3_SHUTDOWN_PLLKW6		0x00000002
+#define KL3_SHUTDOWN_PLLKW4		0x00000004
+#define KL3_SHUTDOWN_PLLKW35		0x00000008
+#define KL3_SHUTDOWN_PLLKW12		0x00000010
+#define KL3_PLL_RESET			0x00000020
+#define KL3_SHUTDOWN_PLL2X		0x00000080
+#define KL3_CLK66_ENABLE		0x00000100
+#define KL3_CLK49_ENABLE		0x00000200
+#define KL3_CLK45_ENABLE		0x00000400
+#define KL3_CLK31_ENABLE		0x00000800
+#define KL3_TIMER_CLK18_ENABLE		0x00001000
+#define KL3_I2S1_CLK18_ENABLE		0x00002000
+#define KL3_I2S0_CLK18_ENABLE		0x00004000
+#define KL3_VIA_CLK16_ENABLE		0x00008000
+#define KL3_STOPPING33_ENABLED		0x00080000
+
+/* Port 0,1 : bus 0, port 2,3 : bus 1 */
+#define KL4_SET_PORT_ENABLE(p)		(0x00000008 << ((p)<<3))
+#define KL4_SET_PORT_RESUME(p)		(0x00000004 << ((p)<<3))
+#define KL4_SET_PORT_CONNECT(p)		(0x00000002 << ((p)<<3))
+#define KL4_SET_PORT_DISCONNECT(p)	(0x00000001 << ((p)<<3))
+#define KL4_GET_PORT_RESUME(p)		(0x00000040 << ((p)<<3))
+#define KL4_GET_PORT_CONNECT(p)		(0x00000020 << ((p)<<3))
+#define KL4_GET_PORT_DISCONNECT(p)	(0x00000010 << ((p)<<3))
+
diff -urN linux-2.2.18-pre20/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- linux-2.2.18-pre20/include/asm-ppc/machdep.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/machdep.h	Mon Dec  3 22:14:18 2001
@@ -30,7 +30,7 @@
 	void		(*power_off)(void);
 	void		(*halt)(void);
 
-	void		(*time_init)(void); /* Optional, may be NULL */
+	long		(*time_init)(void); /* Optional, may be NULL */
 	int		(*set_rtc_time)(unsigned long nowtime);
 	unsigned long	(*get_rtc_time)(void);
 	void		(*calibrate_decr)(void);
@@ -49,8 +49,7 @@
 	void		(*kbd_leds)(unsigned char leds);
 	void		(*kbd_init_hw)(void);
 #ifdef CONFIG_MAGIC_SYSRQ
-	unsigned char 	*kbd_sysrq_xlate;
-	unsigned long	SYSRQ_KEY;
+	unsigned char 	*sysrq_xlate;
 #endif
 
 	/* PCI interfaces */
@@ -67,6 +66,11 @@
 	int (*pcibios_write_config_dword)(unsigned char bus,
 		unsigned char dev_fn, unsigned char offset, unsigned int val);
 	void (*pcibios_fixup)(void);
+
+	void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical);
+	void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn);
+	int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn);
+
 };
 
 extern struct machdep_calls ppc_md;
diff -urN linux-2.2.18-pre20/include/asm-ppc/nvram.h linux/include/asm-ppc/nvram.h
--- linux-2.2.18-pre20/include/asm-ppc/nvram.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/nvram.h	Mon Dec  3 22:14:18 2001
@@ -38,6 +38,8 @@
 	pmac_nvram_NR		/* MacOS Name Registry partition */
 };
 
+#ifdef __KERNEL__
+
 /* Return partition offset in nvram */
 extern int	pmac_get_partition(int partition);
 
@@ -45,15 +47,20 @@
 extern u8	pmac_xpram_read(int xpaddr);
 extern void	pmac_xpram_write(int xpaddr, u8 data);
 
+#endif /* __KERNEL__ */
+
 /* Some offsets in XPRAM */
 #define PMAC_XPRAM_MACHINE_LOC	0xe4
 #define PMAC_XPRAM_SOUND_VOLUME	0x08
 
 /* Machine location structure in XPRAM */
 struct pmac_machine_location {
-	u32	latitude;	/* 2+30 bit Fractional number */
-	u32	longitude;	/* 2+30 bit Fractional number */
-	u32	delta;		/* mix of GMT delta and DLS */
+	unsigned int	latitude;	/* 2+30 bit Fractional number */
+	unsigned int	longitude;	/* 2+30 bit Fractional number */
+	unsigned int	delta;		/* mix of GMT delta and DLS */
 };
+
+/* /dev/nvram ioctls */
+#define PMAC_NVRAM_GET_OFFSET	_IOWR('p', 0x40, int) /* Get NVRAM partition offset */
 
 #endif
diff -urN linux-2.2.18-pre20/include/asm-ppc/pci-bridge.h linux/include/asm-ppc/pci-bridge.h
--- linux-2.2.18-pre20/include/asm-ppc/pci-bridge.h	Tue Apr 14 17:34:00 1998
+++ linux/include/asm-ppc/pci-bridge.h	Mon Dec  3 22:14:18 2001
@@ -6,9 +6,26 @@
 /*
  * pci_io_base returns the memory address at which you can access
  * the I/O space for PCI bus number `bus' (or NULL on error).
+ * 
+ * NOTE: This doesn't handle the new Uni-N chip which requires
+ *       per-device io_base. 
  */
 void *pci_io_base(unsigned int bus);
 
+/* This version handles the new Uni-N host bridge, the iobase is now
+ * a per-device thing. I also added the memory base so PReP can
+ * be fixed to return 0xc0000000 (I didn't actually implement it)
+ *
+ * pci_dev_io_base() returns either a virtual (ioremap'ed) address or
+ * a physical address. In-kernel clients will use logical while the
+ * sys_pciconfig_iobase syscall returns a physical one to userland.
+ */
+void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical);
+void *pci_dev_mem_base(unsigned char bus, unsigned char devfn);
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
+
 /*
  * pci_device_loc returns the bus number and device/function number
  * for a device on a PCI bus, given its device_node struct.
@@ -20,6 +37,7 @@
 struct bridge_data {
 	volatile unsigned int *cfg_addr;
 	volatile unsigned char *cfg_data;
+	void *io_base_phys;
 	void *io_base;
 	int bus_number;
 	int max_bus;
diff -urN linux-2.2.18-pre20/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- linux-2.2.18-pre20/include/asm-ppc/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/pci.h	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,13 @@
+#ifndef __PPC_PCI_H
+#define __PPC_PCI_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+
+/* Values for the `which' argument to sys_pciconfig_iobase.  */
+#define IOBASE_BRIDGE_NUMBER	0
+#define IOBASE_MEMORY		1
+#define IOBASE_IO		2
+
+
+#endif
diff -urN linux-2.2.18-pre20/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- linux-2.2.18-pre20/include/asm-ppc/pmu.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/pmu.h	Mon Dec  3 22:14:18 2001
@@ -10,7 +10,8 @@
 /*
  * PMU commands
  */
-#define PMU_POWER_CTRL		0x11	/* control power of some devices */
+#define PMU_POWER_CTRL0		0x10	/* control power of some devices */
+#define PMU_POWER_CTRL		0x11	/* control power of more devices */
 #define PMU_ADB_CMD		0x20	/* send ADB packet */
 #define PMU_ADB_POLL_OFF	0x21	/* disable ADB auto-poll */
 #define PMU_WRITE_NVRAM		0x33	/* write non-volatile RAM */
@@ -32,11 +33,18 @@
 #define PMU_GET_COVER		0xdc	/* report cover open/closed */
 #define PMU_SYSTEM_READY	0xdf	/* tell PMU we are awake */
 
+/* Bits to use with the PMU_POWER_CTRL0 command */
+#define PMU_POW0_ON		0x80	/* OR this to power ON the device */
+#define PMU_POW0_OFF		0x00	/* leave bit 7 to 0 to power it OFF */
+#define PMU_POW0_HARD_DRIVE	0x04	/* Hard drive power (on wallstreet/lombard ?) */
+
 /* Bits to use with the PMU_POWER_CTRL command */
 #define PMU_POW_ON		0x80	/* OR this to power ON the device */
 #define PMU_POW_OFF		0x00	/* leave bit 7 to 0 to power it OFF */
 #define PMU_POW_BACKLIGHT	0x01	/* backlight power */
+#define PMU_POW_CHARGER		0x02	/* battery charger power */
 #define PMU_POW_IRLED		0x04	/* IR led power (on wallstreet) */
+#define PMU_POW_MEDIABAY	0x08	/* media bay power (wallstreet/lombard ?) */
 
 /* Bits in PMU interrupt and interrupt mask bytes */
 #define PMU_INT_ADB_AUTO	0x04	/* ADB autopoll, when PMU_INT_ADB */
@@ -82,9 +90,9 @@
 
 /* no param */
 #define PMU_IOC_SLEEP		_IO('B', 0)
-/* out param: u32*	backlight value: 0 to 31 */
+/* out param: u32*	backlight value: 0 to 15 */
 #define PMU_IOC_GET_BACKLIGHT	_IOR('B', 1, sizeof(__u32*))
-/* in param: u32	backlight value: 0 to 31 */
+/* in param: u32	backlight value: 0 to 15 */
 #define PMU_IOC_SET_BACKLIGHT	_IOW('B', 2, sizeof(__u32))
 /* out param: u32*	PMU model */
 #define PMU_IOC_GET_MODEL	_IOR('B', 3, sizeof(__u32*))
@@ -93,23 +101,28 @@
 
 #ifdef __KERNEL__
 
-int find_via_pmu(void);
-void via_pmu_init(void);
+extern int find_via_pmu(void);
+extern int via_pmu_start(void);
 
-int pmu_request(struct adb_request *req,
+extern int pmu_request(struct adb_request *req,
 		void (*done)(struct adb_request *), int nbytes, ...);
-void pmu_poll(void);
 
-void pmu_enable_backlight(int on);
-void pmu_set_brightness(int level);
+extern void pmu_poll(void);
+
+/* For use before switching interrupts off for a long time;
+ * warning: not stackable
+ */
+extern void pmu_suspend(void);
+extern void pmu_resume(void);
+
+extern void pmu_enable_irled(int on);
 
-void pmu_enable_irled(int on);
+extern void pmu_restart(void);
+extern void pmu_shutdown(void);
 
-void pmu_restart(void);
-void pmu_shutdown(void);
+extern int pmu_present(void);
+extern int pmu_get_model(void);
 
-int pmu_present(void);
-int pmu_get_model(void);
 
 #ifdef CONFIG_PMAC_PBOOK
 /*
@@ -140,13 +153,14 @@
 #define PBOOK_SLEEP_REFUSE	-1
 
 /* priority levels in notifiers */
-#define SLEEP_LEVEL_VIDEO	100	/* Video driver (first wake) */
-#define SLEEP_LEVEL_SOUND	90	/* Sound driver */
-#define SLEEP_LEVEL_MEDIABAY	80	/* Media bay driver */
-#define SLEEP_LEVEL_BLOCK	70	/* IDE, SCSI */
-#define SLEEP_LEVEL_NET		60	/* bmac */
-#define SLEEP_LEVEL_ADB		50	/* ADB */
-#define SLEEP_LEVEL_MISC	30	/* Anything */
+#define SLEEP_LEVEL_VIDEO	100	/* Video driver */
+#define SLEEP_LEVEL_USB		95	/* USB */
+#define SLEEP_LEVEL_MEDIABAY	90	/* Media bay driver */
+#define SLEEP_LEVEL_NET		80	/* bmac/gmac */
+#define SLEEP_LEVEL_ADB		70	/* ADB */
+#define SLEEP_LEVEL_BLOCK	60	/* IDE, SCSI */
+#define SLEEP_LEVEL_SOUND	50	/* Sound driver */
+#define SLEEP_LEVEL_MISC	40	/* Anything */
 #define SLEEP_LEVEL_LAST	0	/* Anything */
 
 /* special register notifier functions */
diff -urN linux-2.2.18-pre20/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- linux-2.2.18-pre20/include/asm-ppc/processor.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/processor.h	Mon Dec  3 22:14:18 2001
@@ -59,6 +59,15 @@
 #define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
 #define HID0_BTCD	(1<<1)		/* Branch target cache disable */
 
+/* L2CR bits */
+#define L2CR_PIPE_LATEWR   (0x01800000)   /* late-write SRAM */
+#define L2CR_L2CTL         (0x00100000)   /* RAM control */
+#define L2CR_INST_DISABLE  (0x00400000)   /* disable for insn's */
+#define L2CR_L2I           (0x00200000)   /* global invalidate */
+#define L2CR_L2E           (0x80000000)   /* enable */
+#define L2CR_L2WT          (0x00080000)   /* write-through */
+
+ 
 /* fpscr settings */
 #define FPSCR_FX        (1<<31)
 #define FPSCR_FEX       (1<<30)
diff -urN linux-2.2.18-pre20/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- linux-2.2.18-pre20/include/asm-ppc/system.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/system.h	Mon Dec  3 22:14:18 2001
@@ -32,13 +32,6 @@
 	__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
 #define __save_and_cli(flags)	({__save_flags(flags);__cli();})
 
-/* Data cache block flush - write out the cache line containing the
-   specified address and then invalidate it in the cache. */
-extern __inline__ void dcbf(void *line)
-{
-	asm("dcbf %0,%1; sync" : : "r" (line), "r" (0));
-}
-
 extern __inline__ void __restore_flags(unsigned long flags)
 {
         extern atomic_t ppc_n_lost_interrupts;
@@ -67,6 +60,10 @@
 extern int _get_PVR(void);
 extern long _get_L2CR(void);
 extern void _set_L2CR(unsigned long);
+extern long _get_HID0(void);
+extern void _set_HID0(unsigned long);
+extern long _get_ICTC(void);
+extern void _set_ICTC(unsigned long);
 extern void via_cuda_init(void);
 extern void pmac_nvram_init(void);
 extern void read_rtc_time(void);
diff -urN linux-2.2.18-pre20/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h
--- linux-2.2.18-pre20/include/asm-ppc/uaccess.h	Tue Oct 26 17:53:42 1999
+++ linux/include/asm-ppc/uaccess.h	Mon Dec  3 22:14:18 2001
@@ -57,7 +57,7 @@
 
 /* Returns 0 if exception not found and fixup otherwise.  */
 extern unsigned long search_exception_table(unsigned long);
-
+extern void sort_exception_table(void);
 
 /*
  * These are the main single-value transfer routines.  They automatically
diff -urN linux-2.2.18-pre20/include/asm-ppc/ucontext.h linux/include/asm-ppc/ucontext.h
--- linux-2.2.18-pre20/include/asm-ppc/ucontext.h	Mon Jan 12 15:18:13 1998
+++ linux/include/asm-ppc/ucontext.h	Mon Dec  3 22:14:18 2001
@@ -7,6 +7,7 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
+ struct sigcontext_struct uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
 };
 
diff -urN linux-2.2.18-pre20/include/asm-ppc/uninorth.h linux/include/asm-ppc/uninorth.h
--- linux-2.2.18-pre20/include/asm-ppc/uninorth.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/uninorth.h	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,83 @@
+/*
+ * uninorth.h: definitions for using the "UniNorth" host bridge chip
+ *             from Apple. This chip is used on "Core99" machines
+ *
+ */
+
+
+/*
+ * Uni-N config space reg. definitions
+ * 
+ * (Little endian)
+ */
+
+/* Address ranges selection. This one should work with Bandit too */
+#define UNI_N_ADDR_SELECT		0x48
+#define UNI_N_ADDR_COARSE_MASK		0xffff0000	/* 256Mb regions at *0000000 */
+#define UNI_N_ADDR_FINE_MASK		0x0000ffff	/*  16Mb regions at f*000000 */
+
+/* AGP registers */
+#define UNI_N_CFG_GART_BASE		0x8c
+#define UNI_N_CFG_AGP_BASE		0x90
+#define UNI_N_CFG_GART_CTRL		0x94
+#define UNI_N_CFG_INTERNAL_STATUS	0x98
+
+/* UNI_N_CFG_GART_CTRL bits definitions */
+#define UNI_N_CFG_GART_INVAL		0x00000001
+#define UNI_N_CFG_GART_ENABLE		0x00000100
+#define UNI_N_CFG_GART_2xRESET		0x00010000
+
+
+/* 
+ * Uni-N memory mapped reg. definitions
+ * 
+ * Those registers are Big-Endian !!
+ *
+ * Their meaning come from either Darwin and/or from experiments I made with
+ * the bootrom, I'm not sure about their exact meaning yet
+ *
+ */
+
+/* Version of the UniNorth chip */
+#define UNI_N_VERSION			0x0000		/* Known versions: 3,7 and 8 */
+ 
+/* This register is used to enable/disable various parts */
+#define UNI_N_CLOCK_CNTL		0x0020
+#define UNI_N_CLOCK_CNTL_PCI		0x00000001	/* guess ? */
+#define UNI_N_CLOCK_CNTL_GMAC		0x00000002
+#define UNI_N_CLOCK_CNTL_FW		0x00000004	/* guess ? */
+
+/* Power Management control */
+#define UNI_N_POWER_MGT			0x0030
+#define UNI_N_POWER_MGT_NORMAL		0x00
+#define UNI_N_POWER_MGT_IDLE2		0x01
+#define UNI_N_POWER_MGT_SLEEP		0x02
+
+/* This register is configured by Darwin depending on the UniN
+ * revision
+ */
+#define UNI_N_ARB_CTRL			0x0040
+#define UNI_N_ARB_CTRL_QACK_DELAY_SHIFT	15
+#define UNI_N_ARB_CTRL_QACK_DELAY_MASK	0x0e1f8000
+#define UNI_N_ARB_CTRL_QACK_DELAY	0x30
+#define UNI_N_ARB_CTRL_QACK_DELAY105	0x00
+
+/* This one _might_ return the CPU number of the CPU reading it;
+ * the bootROM decides wether to boot or to sleep/spinloop depending
+ * on this register beeing 0 or not
+ */
+#define UNI_N_CPU_NUMBER		0x0050
+
+/* This register appear to be read by the bootROM to decide what
+ *  to do on a non-recoverable reset (powerup or wakeup)
+ */
+#define UNI_N_HWINIT_STATE		0x0070
+#define UNI_N_HWINIT_STATE_SLEEPING	0x01
+#define UNI_N_HWINIT_STATE_RUNNING	0x02
+/* This last bit appear to be used by the bootROM to know the second
+ * CPU has started and will enter it's sleep loop with IP=0
+ */
+#define UNI_N_HWINIT_STATE_CPU1_FLAG	0x10000000
+
+
+
diff -urN linux-2.2.18-pre20/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h
--- linux-2.2.18-pre20/include/asm-ppc/unistd.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-ppc/unistd.h	Mon Dec  3 22:14:18 2001
@@ -195,10 +195,10 @@
 #define __NR_putpmsg		188	/* some people actually want streams */
 #define __NR_vfork		189
 
-#define __NR_sys_pciconfig_read         198
-#define __NR_sys_pciconfig_write        199
-#define __NR_sys_pciconfig_iobase       200
-#define __NR_multiplexer                201
+#define __NR_pciconfig_read     198
+#define __NR_pciconfig_write    199
+#define __NR_pciconfig_iobase   200
+#define __NR_multiplexer        201
 
 #define __NR(n)	#n
 
diff -urN linux-2.2.18-pre20/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h
--- linux-2.2.18-pre20/include/asm-s390/atomic.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/atomic.h	Mon Dec  3 22:14:18 2001
@@ -29,8 +29,8 @@
 {
         int retval;
         __asm__ __volatile__("bcr      15,0\n\t"
-                           "l        %0,%1"
-                           : "=d" (retval) : "m" (*v) );
+                             "l        %0,%1"
+                             : "=d" (retval) : "m" (*v) );
         return retval;
 }
 
@@ -43,98 +43,107 @@
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    2,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    1,0\n"
                              "   ar    1,%1\n"
-                             "   cs    0,1,%0\n"
+                             "   cs    0,1,0(2)\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1", "cc" );
+                             : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    2,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    1,0\n"
                              "   sr    1,%1\n"
-                             "   cs    0,1,%0\n"
+                             "   cs    0,1,0(2)\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1", "cc" );
+                             : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    2,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    1,0\n"
                              "   ahi   1,1\n"
-                             "   cs    0,1,%0\n"
+                             "   cs    0,1,0(2)\n"
                              "   jl    0b"
-                             : "+m" (*v) : : "0", "1", "cc" );
+                             : "+m" (*v) : : "0", "1", "2", "cc" );
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
         int i;
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    1,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    %1,0\n"
                              "   ahi   %1,1\n"
-                             "   cs    0,%1,%0\n"
+                             "   cs    0,%1,0(1)\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
+                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
         return i;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    2,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    1,0\n"
                              "   ahi   1,-1\n"
-                             "   cs    0,1,%0\n"
+                             "   cs    0,1,0(2)\n"
                              "   jl    0b"
-                             : "+m" (*v) : : "0", "1", "cc" );
+                             : "+m" (*v) : : "0", "1", "2", "cc" );
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
         int i;
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    1,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    %1,0\n"
                              "   ahi   %1,-1\n"
-                             "   cs    0,%1,%0\n"
+                             "   cs    0,%1,0(1)\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
+                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
         return i;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
         int i;
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    1,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    %1,0\n"
                              "   ahi   %1,-1\n"
-                             "   cs    0,%1,%0\n"
+                             "   cs    0,%1,0(1)\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "cc");
+                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc");
         return i == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    2,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    1,0\n"
                              "   nr    1,%1\n"
-                             "   cs    0,1,%0\n"
+                             "   cs    0,1,0(2)\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (~(mask)) : "0", "1", "cc" );
+                             : "+m" (*v) : "d" (~(mask)) : "0", "1", "2", "cc" );
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    2,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    1,0\n"
                              "   or    1,%1\n"
-                             "   cs    0,1,%0\n"
+                             "   cs    0,1,0(2)\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (mask) : "0", "1", "cc" );
+                             : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" );
 }
 
 /*
@@ -147,13 +156,15 @@
         int retval;
 
         __asm__ __volatile__(
-                "  cs   %2,%3,%1\n"
+                "  la   1,%1\n"
+                "  lr   0,%2\n"
+                "  cs   0,%3,0(1)\n"
                 "  ipm  %0\n"
                 "  srl  %0,28\n"
                 "0:"
                 : "=&r" (retval), "+m" (*v)
                 : "d" (expected_oldval) , "d" (new_val)
-                : "cc");
+                : "0", "1", "cc");
         return retval;
 }
 
@@ -164,12 +175,13 @@
 atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
 {
         __asm__ __volatile__(
+                "   la  2,%0\n"
                 "0: lr  1,%1\n"
-                "   cs  1,%2,%0\n"
+                "   cs  1,%2,0(2)\n"
                 "   jl  0b\n"
                 : "+m" (*v)
                 : "d" (expected_oldval) , "d" (new_val)
-                : "cc", "1");
+                : "cc", "1", "2");
 }
 
 /*
@@ -178,12 +190,13 @@
 extern __inline__ int atomic_inc_and_test_greater_zero(atomic_t *v)
 {
         int i;
-        __asm__ __volatile__("   l     0,%0\n"
+        __asm__ __volatile__("   la    1,%0\n"
+                             "   l     0,%0\n"
                              "0: lr    %1,0\n"
                              "   ahi   %1,1\n"
-                             "   cs    0,%1,%0\n"
+                             "   cs    0,%1,0(1)\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
+                             : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
         return i > 0;
 }
 
diff -urN linux-2.2.18-pre20/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h
--- linux-2.2.18-pre20/include/asm-s390/bitops.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/bitops.h	Mon Dec  3 22:14:18 2001
@@ -737,24 +737,24 @@
           return 0;
         __asm__("    lr   %%r1,%1\n"
                 "    sr   %0,%0\n"
-                "    tmh  %%r1,0xFFFF\n"
-                "    jz   0f\n"
+                "    tml  %%r1,0xFFFF\n"
+                "    jnz  0f\n"
                 "    ahi  %0,16\n"
                 "    srl  %%r1,16\n"
-                "0:  tml  %%r1,0xFF00\n"
-                "    jz   1f\n"
+                "0:  tml  %%r1,0x00FF\n"
+                "    jnz  1f\n"
                 "    ahi  %0,8\n"
                 "    srl  %%r1,8\n"
-                "1:  tml  %%r1,0x00F0\n"
-                "    jz   2f\n"
+                "1:  tml  %%r1,0x000F\n"
+                "    jnz  2f\n"
                 "    ahi  %0,4\n"
                 "    srl  %%r1,4\n"
-                "2:  tml  %%r1,0x000C\n"
-                "    jz   3f\n"
+                "2:  tml  %%r1,0x0003\n"
+                "    jnz  3f\n"
                 "    ahi  %0,2\n"
                 "    srl  %%r1,2\n"
-                "3:  tml  %%r1,0x0002\n"
-                "    jz   4f\n"
+                "3:  tml  %%r1,0x0001\n"
+                "    jnz  4f\n"
                 "    ahi  %0,1\n"
                 "4:"
                 : "=&d" (r) : "d" (x) : "cc", "1" );
diff -urN linux-2.2.18-pre20/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h
--- linux-2.2.18-pre20/include/asm-s390/ccwcache.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/ccwcache.h	Mon Dec  3 22:14:18 2001
@@ -57,13 +57,14 @@
 /* 
  * ccw_req_t -> status can be:
  */
-#define CQR_STATUS_EMPTY  0x00	/* request is empty */
-#define CQR_STATUS_FILLED 0x01	/* request is ready to be preocessed */
-#define CQR_STATUS_QUEUED 0x02	/* request is queued to be processed */
-#define CQR_STATUS_IN_IO  0x04	/* request is currently in IO */
-#define CQR_STATUS_DONE   0x08	/* request is completed sucessfully */
-#define CQR_STATUS_ERROR  0x10	/* request is completed with error */
-#define CQR_STATUS_FAILED 0x20	/* request is finally failed */
+#define CQR_STATUS_EMPTY    0x00	/* request is empty */
+#define CQR_STATUS_FILLED   0x01	/* request is ready to be preocessed */
+#define CQR_STATUS_QUEUED   0x02	/* request is queued to be processed */
+#define CQR_STATUS_IN_IO    0x04	/* request is currently in IO */
+#define CQR_STATUS_DONE     0x08	/* request is completed sucessfully */
+#define CQR_STATUS_ERROR    0x10	/* request is completed with error */
+#define CQR_STATUS_FAILED   0x20	/* request is finally failed */
+#define CQR_STATUS_FINISHED 0x40	/* request is ready for cleanup */
 
 #ifdef __KERNEL__
 #define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\
diff -urN linux-2.2.18-pre20/include/asm-s390/checksum.h linux/include/asm-s390/checksum.h
--- linux-2.2.18-pre20/include/asm-s390/checksum.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/checksum.h	Mon Dec  3 22:14:18 2001
@@ -92,7 +92,7 @@
  *      Fold a partial checksum without adding pseudo headers
  */
 #if 1
-unsigned short csum_fold(unsigned int sum);
+extern unsigned short csum_fold(unsigned int sum);
 #else
 extern inline unsigned short
 csum_fold(unsigned int sum)
@@ -141,20 +141,19 @@
                    unsigned int sum)
 {
 	__asm__ __volatile__ (
-		"    sll   %3,16\n"
-		"    or    %3,%4\n"  /* newproto=proto<<16 in hiword, len in lowword */
-		"    alr   %1,%2\n"  /* saddr+=daddr */
-		"    brc   12,0f\n"
-		"    ahi   %1,1\n"   /* add carry */
-		"0:  alr   %1,%3\n"  /* add saddr+=newproto */
-		"    brc   12,1f\n"
-		"    ahi   %1,1\n"   /* add carry again */
-		"1:  alr   %0,%1\n"  /* sum+=saddr */
+                "    alr   %0,%1\n"  /* sum += saddr */
+                "    brc   12,0f\n"
+		"    ahi   %0,1\n"   /* add carry */
+		"0:  alr   %0,%2\n"  /* sum += daddr */
+                "    brc   12,1f\n"
+                "    ahi   %0,1\n"   /* add carry */
+		"1:  alr   %0,%3\n"  /* sum += (len<<16) + (proto<<8) */
 		"    brc   12,2f\n"
-		"    ahi   %0,1\n"   /* add carry again */
+		"    ahi   %0,1\n"   /* add carry */
 		"2:"
 		: "+&d" (sum)
-		: "d" (saddr), "d" (daddr), "d" (proto), "d" (len)
+		: "d" (saddr), "d" (daddr),
+		  "d" (((unsigned int) len<<16) + (unsigned int) proto)
 		: "cc" );
 	return sum;
 }
diff -urN linux-2.2.18-pre20/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- linux-2.2.18-pre20/include/asm-s390/dasd.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/dasd.h	Mon Dec  3 22:14:18 2001
@@ -3,11 +3,14 @@
 #define DASD_H
 
 /* First of all the external stuff */
+#include <linux/version.h>
 #include <linux/ioctl.h>
 #include <linux/major.h>
 #include <linux/wait.h>
 #include <asm/ccwcache.h>
-/* #include <linux/blkdev.h> */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/blkdev.h> 
+#endif
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/version.h>
diff -urN linux-2.2.18-pre20/include/asm-s390/debug.h linux/include/asm-s390/debug.h
--- linux-2.2.18-pre20/include/asm-s390/debug.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/debug.h	Mon Dec  3 22:14:18 2001
@@ -1,57 +1,118 @@
+/*
+ *  include/asm-s390/debug.h
+ *   S/390 debug facility
+ *
+ *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ *                             IBM Corporation
+ */
+
 #ifndef DEBUG_H
 #define DEBUG_H
 
-#include <asm/spinlock.h>
-
 #ifdef __KERNEL__
 
-#define MAX_DEBUG_AREAS 16
-
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
+#include <asm/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
+
+#define DEBUG_MAX_AREAS            16 /* max number of allowed registers */
+#define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
+#define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
+#define DEBUG_MAX_PROCF_LEN        16 /* max length for a proc file name */
+#define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
+
+#define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
+
+#define STCK(x)	asm volatile ("STCK %0":"=m" (x))
+
+typedef struct {
+	union {
+		struct {
+			unsigned long long clock:52;
+			unsigned long long unused:2;
+			unsigned long long cpuid:8;
+			unsigned long long exception:1;
+			unsigned long long used:1;
+		} fields;
+
+		unsigned long long stck;
+	} id;
+	void* caller;
+	char data[4];
+} debug_entry_t;
+
+struct debug_view;
+
+typedef struct {	
+	atomic_t ref_count;
+	spinlock_t lock;			
+	int level;
+	int nr_areas;
+	int page_order;
+	int buf_size;
+	int entry_size;	
+	debug_entry_t** areas;
+	int active_area;
+	int active_entry[DEBUG_MAX_AREAS];
+	struct proc_dir_entry* proc_root_entry;
+	struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS];
+	struct debug_view* views[DEBUG_MAX_VIEWS];	
+	char name[DEBUG_MAX_PROCF_LEN];
+} debug_info_t;
+
+typedef int (debug_header_proc_t) (debug_info_t* id,
+				   struct debug_view* view,
+				   int area,
+				   debug_entry_t* entry,
+				   char* out_buf);
+
+typedef int (debug_format_proc_t) (debug_info_t* id,
+				   struct debug_view* view, char* out_buf,
+				   const char* in_buf);
+typedef int (debug_prolog_proc_t) (debug_info_t* id,
+				   struct debug_view* view,
+				   char* out_buf);
+typedef int (debug_input_proc_t) (debug_info_t* id,
+				  struct debug_view* view,
+				  struct file* file, const char* user_buf,
+				  size_t in_buf_size, loff_t* offset);
+
+int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view,
+		         int area, debug_entry_t* entry, char* out_buf);						
+				
+struct debug_view {
+	char name[DEBUG_MAX_PROCF_LEN];
+	debug_prolog_proc_t* prolog_proc;
+	debug_header_proc_t* header_proc;
+	debug_format_proc_t* format_proc;
+	debug_input_proc_t*  input_proc;
+};
+
+extern struct debug_view debug_ascii_view;
+extern struct debug_view debug_ebcdic_view;
+extern struct debug_view debug_hex_view;
+
+debug_info_t* debug_register(char* name, int pages_index, int nr_areas,
+			     int buf_size);
+void debug_unregister(debug_info_t* id);
+
+debug_entry_t* debug_event(debug_info_t* id, int level, void* data,
+			   int length);
+debug_entry_t* debug_int_event(debug_info_t* id, int level,
+			       unsigned int tag);
+debug_entry_t* debug_text_event(debug_info_t* id, int level,
+				const char* txt);
+
+debug_entry_t* debug_exception(debug_info_t* id, int level, void* data,
+			       int length);
+debug_entry_t* debug_int_exception(debug_info_t* id, int level,
+				   unsigned int tag);
+debug_entry_t* debug_text_exception(debug_info_t* id, int level,
+				    const char* txt);
 
-typedef struct
-{
-  union
-  {
-    struct
-    {
-      unsigned long long cpuid:4;
-      unsigned long long clock:60;
-    }
-    fields;
-    unsigned long long stck;
-  }
-  id;
-  void *caller;
-  union
-  {
-    unsigned long tag;
-    char text[4];
-  }
-  tag;
-}
-debug_entry_t;
-
-typedef struct
-{
-  char *name;
-  int level;
-  int nr_areas;
-  int page_order;
-  debug_entry_t **areas;
-  int active_area;
-  int *active_entry;
-  spinlock_t lock;
-}
-debug_info_t;
-
-int debug_init (void);
-debug_info_t *debug_register (char *name, int pages_index, int nr_areas);
-void debug_unregister (debug_info_t * id, char *name);
-void debug_event (debug_info_t * id, int level, unsigned int tag);
-void debug_text_event (debug_info_t * id, int level, char tag[4]);
-void debug_exception (debug_info_t * id, int level, unsigned int tag);
-void debug_text_exception (debug_info_t * id, int level, char tag[4]);
+int debug_register_view(debug_info_t* id, struct debug_view* view);
+int debug_unregister_view(debug_info_t* id, struct debug_view* view);
 
 /*
    define the debug levels:
diff -urN linux-2.2.18-pre20/include/asm-s390/idals.h linux/include/asm-s390/idals.h
--- linux-2.2.18-pre20/include/asm-s390/idals.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/idals.h	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,25 @@
+/* 
+   * File...........: linux/include/asm-s390x/idals.h
+   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+   * Bugreports.to..: <Linux390@de.ibm.com>
+   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+   
+   * History of changes
+   * 07/24/00 new file
+ */
+
+#define IDAL_NUMBER_CACHES 7
+
+typedef unsigned long idaw_t;
+
+#ifdef CONFIG_ARCH_S390
+extern inline int 
+normalize_cpa(ccw1_t * ccw, unsigned long address)
+{
+	return address;
+}
+#endif
+
+int idal_alloc ( int nridaws );
+void idal_release ( idaw_t *idal );
+
diff -urN linux-2.2.18-pre20/include/asm-s390/irq.h linux/include/asm-s390/irq.h
--- linux-2.2.18-pre20/include/asm-s390/irq.h	Mon Dec  3 22:14:09 2001
+++ linux/include/asm-s390/irq.h	Mon Dec  3 22:14:18 2001
@@ -22,7 +22,7 @@
  * to describe about the low-level hardware.
  */
 struct hw_interrupt_type {
-        const char   *typename;
+        const __u8   *typename;
         int         (*handle)(unsigned int irq,
                               int cpu,
                               struct pt_regs * regs);
@@ -43,60 +43,59 @@
  * path management control word
  */
 typedef struct {
-      unsigned long  intparm;      /* interruption parameter */
-      unsigned int   res0 : 2;     /* reserved zeros */
-      unsigned int   isc  : 3;     /* interruption sublass */
-      unsigned int   res5 : 3;     /* reserved zeros */
-      unsigned int   ena  : 1;     /* enabled */
-      unsigned int   lm   : 2;     /* limit mode */
-      unsigned int   mme  : 2;     /* measurement-mode enable */
-      unsigned int   mp   : 1;     /* multipath mode */
-      unsigned int   tf   : 1;     /* timing facility */
-      unsigned int   dnv  : 1;     /* device number valid */
-      unsigned int   dev  : 16;    /* device number */
-      unsigned char  lpm;          /* logical path mask */
-      unsigned char  pnom;         /* path not operational mask */
-      unsigned char  lpum;         /* last path used mask */
-      unsigned char  pim;          /* path installed mask */
-      unsigned short mbi;          /* measurement-block index */
-      unsigned char  pom;          /* path operational mask */
-      unsigned char  pam;          /* path available mask */
-      unsigned char  chpid[8];     /* CHPID 0-7 (if available) */
-      unsigned int   unused1 : 8;  /* reserved zeros */
-      unsigned int   st      : 3;  /* subchannel type */
-      unsigned int   unused2 : 20; /* reserved zeros */
-      unsigned int   csense  : 1;  /* concurrent sense; can be enabled ...*/
-                                   /*  ... per MSCH, however, if facility */
-                                   /*  ... is not installed, this results */
-                                   /*  ... in an operand exception.       */
+      __u32 intparm;      /* interruption parameter */
+      __u32 res0 : 2;     /* reserved zeros */
+      __u32 isc  : 3;     /* interruption sublass */
+      __u32 res5 : 3;     /* reserved zeros */
+      __u32 ena  : 1;     /* enabled */
+      __u32 lm   : 2;     /* limit mode */
+      __u32 mme  : 2;     /* measurement-mode enable */
+      __u32 mp   : 1;     /* multipath mode */
+      __u32 tf   : 1;     /* timing facility */
+      __u32 dnv  : 1;     /* device number valid */
+      __u32 dev  : 16;    /* device number */
+      __u8  lpm;          /* logical path mask */
+      __u8  pnom;         /* path not operational mask */
+      __u8  lpum;         /* last path used mask */
+      __u8  pim;          /* path installed mask */
+      __u16 mbi;          /* measurement-block index */
+      __u8  pom;          /* path operational mask */
+      __u8  pam;          /* path available mask */
+      __u8  chpid[8];     /* CHPID 0-7 (if available) */
+      __u32 unused1 : 8;  /* reserved zeros */
+      __u32 st      : 3;  /* subchannel type */
+      __u32 unused2 : 20; /* reserved zeros */
+      __u32 csense  : 1;  /* concurrent sense; can be enabled ...*/
+                          /*  ... per MSCH, however, if facility */
+                          /*  ... is not installed, this results */
+                          /*  ... in an operand exception.       */
    } __attribute__ ((packed)) pmcw_t;
 
 #endif /* __KERNEL__ */
-
 /*
  * subchannel status word
  */
 typedef struct {
-      unsigned int   key  : 4; /* subchannel key */
-      unsigned int   sctl : 1; /* suspend control */
-      unsigned int   eswf : 1; /* ESW format */
-      unsigned int   cc   : 2; /* deferred condition code */
-      unsigned int   fmt  : 1; /* format */
-      unsigned int   pfch : 1; /* prefetch */
-      unsigned int   isic : 1; /* initial-status interruption control */
-      unsigned int   alcc : 1; /* address-limit checking control */
-      unsigned int   ssi  : 1; /* supress-suspended interruption */
-      unsigned int   zcc  : 1; /* zero condition code */
-      unsigned int   ectl : 1; /* extended control */
-      unsigned int   pno  : 1;     /* path not operational */
-      unsigned int   res  : 1;     /* reserved */
-      unsigned int   fctl : 3;     /* function control */
-      unsigned int   actl : 7;     /* activity control */
-      unsigned int   stctl : 5;    /* status control */
-      unsigned long  cpa;          /* channel program address */
-      unsigned int   dstat : 8;    /* device status */
-      unsigned int   cstat : 8;    /* subchannel status */
-      unsigned int   count : 16;   /* residual count */
+      __u32 key  : 4; /* subchannel key */
+      __u32 sctl : 1; /* suspend control */
+      __u32 eswf : 1; /* ESW format */
+      __u32 cc   : 2; /* deferred condition code */
+      __u32 fmt  : 1; /* format */
+      __u32 pfch : 1; /* prefetch */
+      __u32 isic : 1; /* initial-status interruption control */
+      __u32 alcc : 1; /* address-limit checking control */
+      __u32 ssi  : 1; /* supress-suspended interruption */
+      __u32 zcc  : 1; /* zero condition code */
+      __u32 ectl : 1; /* extended control */
+      __u32 pno  : 1;     /* path not operational */
+      __u32 res  : 1;     /* reserved */
+      __u32 fctl : 3;     /* function control */
+      __u32 actl : 7;     /* activity control */
+      __u32 stctl : 5;    /* status control */
+      __u32 cpa;          /* channel program address */
+      __u32 dstat : 8;    /* device status */
+      __u32 cstat : 8;    /* subchannel status */
+      __u32 count : 16;   /* residual count */
    } __attribute__ ((packed)) scsw_t;
 
 #define SCSW_FCTL_CLEAR_FUNC     0x1
@@ -136,24 +135,22 @@
 #define SCHN_STAT_CHAIN_CHECK    0x01
 
 #ifdef __KERNEL__
-
 /*
  * subchannel information block
  */
 typedef struct {
       pmcw_t pmcw;             /* path management control word */
       scsw_t scsw;             /* subchannel status word */
-      char mda[12];            /* model dependent area */
-   } schib_t __attribute__ ((packed,aligned(4)));
-
+      __u8 mda[12];            /* model dependent area */
+   } __attribute__ ((packed,aligned(4))) schib_t;
 #endif /* __KERNEL__ */
 
 typedef struct {
-      char            cmd_code;/* command code */
-      char            flags;   /* flags, like IDA adressing, etc. */
-      unsigned short  count;   /* byte count */
-      void           *cda;     /* data address */
-   } ccw1_t __attribute__ ((aligned(8)));
+      __u8  cmd_code;/* command code */
+      __u8  flags;   /* flags, like IDA adressing, etc. */
+      __u16 count;   /* byte count */
+      __u32 cda;     /* data address */
+   } __attribute__ ((packed,aligned(8))) ccw1_t;
 
 #define CCW_FLAG_DC             0x80
 #define CCW_FLAG_CC             0x40
@@ -174,7 +171,6 @@
 #define CCW_CMD_SENSE_ID        0xE4
 
 #ifdef __KERNEL__
-
 #define SENSE_MAX_COUNT         0x20
 
 /*
@@ -192,101 +188,100 @@
  * operation request block
  */
 typedef struct {
-      unsigned long  intparm;  /* interruption parameter */
-      unsigned int   key  : 4; /* flags, like key, suspend control, etc. */
-      unsigned int   spnd : 1; /* suspend control */
-      unsigned int   res1 : 3; /* reserved */
-      unsigned int   fmt  : 1; /* format control */
-      unsigned int   pfch : 1; /* prefetch control */
-      unsigned int   isic : 1; /* initial-status-interruption control */
-      unsigned int   alcc : 1; /* address-limit-checking control */
-      unsigned int   ssic : 1; /* suppress-suspended-interr. control */
-      unsigned int   res2 : 3; /* reserved */
-      unsigned int   lpm  : 8; /* logical path mask */
-      unsigned int   ils  : 1; /* incorrect length */
-      unsigned int   zero : 7; /* reserved zeros */
-      ccw1_t        *cpa;      /* channel program address */
+      __u32 intparm;  /* interruption parameter */
+      __u32 key  : 4; /* flags, like key, suspend control, etc. */
+      __u32 spnd : 1; /* suspend control */
+      __u32 res1 : 3; /* reserved */
+      __u32 fmt  : 1; /* format control */
+      __u32 pfch : 1; /* prefetch control */
+      __u32 isic : 1; /* initial-status-interruption control */
+      __u32 alcc : 1; /* address-limit-checking control */
+      __u32 ssic : 1; /* suppress-suspended-interr. control */
+      __u32 res2 : 3; /* reserved */
+      __u32 lpm  : 8; /* logical path mask */
+      __u32 ils  : 1; /* incorrect length */
+      __u32 zero : 7; /* reserved zeros */
+      __u32 cpa;      /* channel program address */
    }  __attribute__ ((packed,aligned(4))) orb_t;
 
 #endif /* __KERNEL__ */
-
 typedef struct {
-      unsigned int res0  : 4;  /* reserved */
-      unsigned int pvrf  : 1;  /* path-verification-required flag */
-      unsigned int cpt   : 1;  /* channel-path timeout */
-      unsigned int fsavf : 1;  /* Failing storage address validity flag */
-      unsigned int cons  : 1;  /* concurrent-sense */
-      unsigned int res8  : 2;  /* reserved */
-      unsigned int scnt  : 6;  /* sense count if cons == 1 */
-      unsigned int res16 : 16; /* reserved */
-   } erw_t;
+      __u32 res0  : 4;  /* reserved */
+      __u32 pvrf  : 1;  /* path-verification-required flag */
+      __u32 cpt   : 1;  /* channel-path timeout */
+      __u32 fsavf : 1;  /* Failing storage address validity flag */
+      __u32 cons  : 1;  /* concurrent-sense */
+      __u32 res8  : 2;  /* reserved */
+      __u32 scnt  : 6;  /* sense count if cons == 1 */
+      __u32 res16 : 16; /* reserved */
+   } __attribute__ ((packed)) erw_t;
 
 /*
  * subchannel logout area
  */
 typedef struct {
-      unsigned int res0  : 1;  /* reserved */
-      unsigned int esf   : 7;  /* extended status flags */
-      unsigned int lpum  : 8;  /* last path used mask */
-      unsigned int res16 : 1;  /* reserved */
-      unsigned int fvf   : 5;  /* field-validity flags */
-      unsigned int sacc  : 2;  /* storage access code */
-      unsigned int termc : 2;  /* termination code */
-      unsigned int devsc : 1;  /* device-status check */
-      unsigned int serr  : 1;  /* secondary error */
-      unsigned int ioerr : 1;  /* i/o-error alert */
-      unsigned int seqc  : 3;  /* sequence code */
-   } sublog_t ;
+      __u32 res0  : 1;  /* reserved */
+      __u32 esf   : 7;  /* extended status flags */
+      __u32 lpum  : 8;  /* last path used mask */
+      __u32 res16 : 1;  /* reserved */
+      __u32 fvf   : 5;  /* field-validity flags */
+      __u32 sacc  : 2;  /* storage access code */
+      __u32 termc : 2;  /* termination code */
+      __u32 devsc : 1;  /* device-status check */
+      __u32 serr  : 1;  /* secondary error */
+      __u32 ioerr : 1;  /* i/o-error alert */
+      __u32 seqc  : 3;  /* sequence code */
+   } __attribute__ ((packed)) sublog_t ;
 
 /*
  * Format 0 Extended Status Word (ESW)
  */
 typedef struct {
-      sublog_t      sublog;    /* subchannel logout */
-      erw_t         erw;       /* extended report word */
-      void         *faddr;     /* failing address */
-      unsigned int  zeros[2];  /* 2 fullwords of zeros */
-   } esw0_t;
+      sublog_t sublog;    /* subchannel logout */
+      erw_t    erw;       /* extended report word */
+      __u32    faddr;     /* failing address */
+      __u32    zeros[2];  /* 2 fullwords of zeros */
+   } __attribute__ ((packed)) esw0_t;
 
 /*
  * Format 1 Extended Status Word (ESW)
  */
 typedef struct {
-      unsigned char  zero0;    /* reserved zeros */
-      unsigned char  lpum;     /* last path used mask */
-      unsigned short zero16;   /* reserved zeros */
-      erw_t          erw;      /* extended report word */
-      unsigned int   zeros[3]; /* 2 fullwords of zeros */
-   } esw1_t;
+      __u8  zero0;    /* reserved zeros */
+      __u8  lpum;     /* last path used mask */
+      __u16 zero16;   /* reserved zeros */
+      erw_t erw;      /* extended report word */
+      __u32 zeros[3]; /* 2 fullwords of zeros */
+   } __attribute__ ((packed)) esw1_t;
 
 /*
  * Format 2 Extended Status Word (ESW)
  */
 typedef struct {
-      unsigned char  zero0;    /* reserved zeros */
-      unsigned char  lpum;     /* last path used mask */
-      unsigned short dcti;     /* device-connect-time interval */
-      erw_t          erw;      /* extended report word */
-      unsigned int   zeros[3]; /* 2 fullwords of zeros */
-   } esw2_t;
+      __u8  zero0;    /* reserved zeros */
+      __u8  lpum;     /* last path used mask */
+      __u16 dcti;     /* device-connect-time interval */
+      erw_t erw;      /* extended report word */
+      __u32 zeros[3]; /* 2 fullwords of zeros */
+   } __attribute__ ((packed)) esw2_t;
 
 /*
  * Format 3 Extended Status Word (ESW)
  */
 typedef struct {
-      unsigned char  zero0;    /* reserved zeros */
-      unsigned char  lpum;     /* last path used mask */
-      unsigned short res;      /* reserved */
-      erw_t          erw;      /* extended report word */
-      unsigned int   zeros[3]; /* 2 fullwords of zeros */
-   } esw3_t;
+      __u8  zero0;    /* reserved zeros */
+      __u8  lpum;     /* last path used mask */
+      __u16 res;      /* reserved */
+      erw_t erw;      /* extended report word */
+      __u32 zeros[3]; /* 2 fullwords of zeros */
+   } __attribute__ ((packed)) esw3_t;
 
 typedef union {
       esw0_t esw0;
       esw1_t esw1;
       esw2_t esw2;
       esw3_t esw3;
-   } esw_t;
+   } __attribute__ ((packed)) esw_t;
 
 /*
  * interruption response block
@@ -294,30 +289,31 @@
 typedef struct {
       scsw_t scsw;             /* subchannel status word */
       esw_t  esw;              /* extended status word */
-      char   ecw[32];          /* extended control word */
-   } irb_t __attribute__ ((aligned(4)));
-
+      __u8   ecw[32];          /* extended control word */
+   } irb_t __attribute__ ((packed,aligned(4)));
 #ifdef __KERNEL__
 
 /*
  * TPI info structure
  */
 typedef struct {
-      unsigned int res : 16;   /* reserved 0x00000001 */
-      unsigned int irq : 16;   /* aka. subchannel number */
-      unsigned int intparm;    /* interruption parameter */
-   } tpi_info_t;
+      __u32 res : 16;   /* reserved 0x00000001 */
+      __u32 irq : 16;   /* aka. subchannel number */
+      __u32 intparm;    /* interruption parameter */
+   } __attribute__ ((packed)) tpi_info_t;
+
+
 
 //
 // command information word  (CIW) layout
 //
 typedef struct _ciw {
-   unsigned int et       :  2; // entry type
-   unsigned int reserved :  2; // reserved
-   unsigned int ct       :  4; // command type
-   unsigned int cmd      :  8; // command
-   unsigned int count    : 16; // count
-   } ciw_t;
+   __u32        et       :  2; // entry type
+   __u32        reserved :  2; // reserved
+   __u32        ct       :  4; // command type
+   __u32        cmd      :  8; // command
+   __u32        count    : 16; // count
+   } __attribute__ ((packed)) ciw_t;
 
 #define CIW_TYPE_RCD    0x0    // read configuration data
 #define CIW_TYPE_SII    0x1    // set interface identifier
@@ -328,26 +324,24 @@
 //
 typedef struct {
   /* common part */
-      unsigned char  reserved;     /* always 0x'FF' */
-      unsigned short cu_type;      /* control unit type */
-      unsigned char  cu_model;     /* control unit model */
-      unsigned short dev_type;     /* device type */
-      unsigned char  dev_model;    /* device model */
-      unsigned char  unused;       /* padding byte */
+      __u8           reserved;     /* always 0x'FF' */
+      __u16          cu_type;      /* control unit type */
+      __u8           cu_model;     /* control unit model */
+      __u16          dev_type;     /* device type */
+      __u8           dev_model;    /* device model */
+      __u8           unused;       /* padding byte */
   /* extended part */
       ciw_t    ciw[16];            /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
 #endif /* __KERNEL__ */
-
 /*
  * sense data
  */
 typedef struct {
-      unsigned char res[32];   /* reserved   */
-      unsigned char data[32];  /* sense data */
-   } sense_t;
-
+      __u8          res[32];   /* reserved   */
+      __u8          data[32];  /* sense data */
+   } __attribute__ ((packed)) sense_t;
 
 /*
  * device status area, to be provided by the device driver
@@ -359,15 +353,15 @@
  */
 typedef struct {
      unsigned int  devno;    /* device number, aka. "cuu" from irb */
-     unsigned int  intparm;  /* interrupt parameter */
-     unsigned char cstat;    /* channel status - accumulated */
-     unsigned char dstat;    /* device status - accumulated */
-     unsigned char lpum;     /* last path used mask from irb */
-     unsigned char unused;   /* not used - reserved */
+     unsigned long intparm;  /* interrupt parameter */
+     __u8          cstat;    /* channel status - accumulated */
+     __u8          dstat;    /* device status - accumulated */
+     __u8          lpum;     /* last path used mask from irb */
+     __u8          unused;   /* not used - reserved */
      unsigned int  flag;     /* flag : see below */
-     unsigned long cpa;      /* CCW address from irb at primary status */
-     unsigned int  rescnt;   /* res. count from irb at primary status */
-     unsigned int  scnt;     /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
+     __u32         cpa;      /* CCW address from irb at primary status */
+     __u32         rescnt;   /* res. count from irb at primary status */
+     __u32         scnt;     /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
      union {
         irb_t   irb;         /* interruption response block */
         sense_t sense;       /* sense information */
@@ -389,20 +383,18 @@
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
-
 #ifdef __KERNEL__
 
-typedef  void (* io_handler_func1_t) ( int  irq,
-                                       devstat_t *devstat,
+typedef  void (* io_handler_func1_t) ( int             irq,
+                                       devstat_t      *devstat,
                                        struct pt_regs *rgs);
 
-typedef  void (* io_handler_func_t) ( int  irq,
+typedef  void (* io_handler_func_t) ( int             irq,
                                       void           *devstat,
                                       struct pt_regs *rgs);
 
 typedef  void ( * not_oper_handler_func_t)( int irq,
                                             int status );
-
 struct s390_irqaction {
 	io_handler_func_t  handler;
 	unsigned long      flags;
@@ -410,7 +402,6 @@
 	devstat_t         *dev_id;
 };
 
-
 /*
  * This is the "IRQ descriptor", which contains various information
  * about the irq, including what kind of hardware handling it has,
@@ -465,7 +456,7 @@
 #define DOIO_EARLY_NOTIFICATION  0x0001 /* allow for I/O completion ... */
                                         /* ... notification after ... */
                                         /* ... primary interrupt status */
-#define DOIO_RETURN_CHAN_END       DOIO_EARLY_NOTIFICATION
+#define DOIO_RETURN_CHAN_END     DOIO_EARLY_NOTIFICATION
 #define DOIO_VALID_LPM           0x0002 /* LPM input parameter is valid */
 #define DOIO_WAIT_FOR_INTERRUPT  0x0004 /* wait synchronously for interrupt */
 #define DOIO_REPORT_ALL          0x0008 /* report all interrupt conditions */
@@ -494,22 +485,22 @@
  */
 int do_IO( int            irq,          /* IRQ aka. subchannel number */
            ccw1_t        *cpa,          /* logical channel program address */
-           unsigned long  initparm,     /* interruption parameter */
-           unsigned char  lpm,          /* logical path mask */
+           unsigned long  intparm,      /* interruption parameter */
+           __u8           lpm,          /* logical path mask */
            unsigned long  flag);        /* flags : see above */
 
-int start_IO( int            irq,       /* IRQ aka. subchannel number */
-              ccw1_t        *cpa,       /* logical channel program address */
+int start_IO( int           irq,       /* IRQ aka. subchannel number */
+              ccw1_t       *cpa,       /* logical channel program address */
               unsigned long  intparm,   /* interruption parameter */
-              unsigned char  lpm,       /* logical path mask */
-              unsigned long  flag);     /* flags : see above */
+              __u8          lpm,       /* logical path mask */
+              unsigned int  flag);     /* flags : see above */
 
 void do_crw_pending( void  );	         /* CRW handler */
 
-int resume_IO( int irq);                /* IRQ aka. subchannel number */
+int resume_IO( int irq);               /* IRQ aka. subchannel number */
 
-int halt_IO( int           irq,      /* IRQ aka. subchannel number */
-             unsigned long intparm,  /* dummy intparm */
+int halt_IO( int           irq,         /* IRQ aka. subchannel number */
+             unsigned long intparm,     /* dummy intparm */
              unsigned long flag);       /* possible DOIO_WAIT_FOR_INTERRUPT */
 
 int clear_IO( int           irq,         /* IRQ aka. subchannel number */
@@ -545,7 +536,7 @@
 int read_dev_chars( int irq, void **buffer, int length );
 int read_conf_data( int irq, void **buffer, int *length, __u8 lpm );
 
-int s390_DevicePathVerification( int irq, __u8 domask );
+int  s390_DevicePathVerification( int irq, __u8 domask );
 
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
@@ -714,21 +705,35 @@
         return ccode;
 }
 
+extern __inline__ int rchp(int chpid)
+{
+        int ccode;
+
+        __asm__ __volatile__(
+                "LR 1,%1\n\t"
+                "RCHP\n\t"
+                "IPM %0\n\t"
+                "SRL %0,28\n\t"
+                : "=d" (ccode) : "r" (chpid)
+                : "cc", "1" );
+        return ccode;
+}
+
 typedef struct {
-     unsigned int vrdcdvno : 16;   /* device number (input) */
-     unsigned int vrdclen  : 16;   /* data block length (input) */
-     unsigned int vrdcvcla : 8;    /* virtual device class (output) */
-     unsigned int vrdcvtyp : 8;    /* virtual device type (output) */
-     unsigned int vrdcvsta : 8;    /* virtual device status (output) */
-     unsigned int vrdcvfla : 8;    /* virtual device flags (output) */
-     unsigned int vrdcrccl : 8;    /* real device class (output) */
-     unsigned int vrdccrty : 8;    /* real device type (output) */
-     unsigned int vrdccrmd : 8;    /* real device model (output) */
-     unsigned int vrdccrft : 8;    /* real device feature (output) */
+     __u16 vrdcdvno : 16;   /* device number (input) */
+     __u16 vrdclen  : 16;   /* data block length (input) */
+     __u32 vrdcvcla : 8;    /* virtual device class (output) */
+     __u32 vrdcvtyp : 8;    /* virtual device type (output) */
+     __u32 vrdcvsta : 8;    /* virtual device status (output) */
+     __u32 vrdcvfla : 8;    /* virtual device flags (output) */
+     __u32 vrdcrccl : 8;    /* real device class (output) */
+     __u32 vrdccrty : 8;    /* real device type (output) */
+     __u32 vrdccrmd : 8;    /* real device model (output) */
+     __u32 vrdccrft : 8;    /* real device feature (output) */
      } __attribute__ ((packed,aligned(4))) diag210_t;
 
-void VM_virtual_device_info( unsigned int  devno, /* device number */
-                             senseid_t    *ps );  /* ptr to senseID data */
+void VM_virtual_device_info( unsigned int devno, /* device number */
+                             senseid_t *ps );    /* ptr to senseID data */
 
 extern __inline__ int diag210( diag210_t * addr)
 {
@@ -758,7 +763,7 @@
 
 extern spinlock_t irq_controller_lock;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #include <asm/atomic.h>
 
@@ -779,28 +784,27 @@
 
 #else
 
-#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
-#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
+#define irq_enter(cpu, irq)     (++local_irq_count(cpu))
+#define irq_exit(cpu, irq)      (--local_irq_count(cpu))
 
 #endif
 
 #define __STR(x) #x
 #define STR(x) __STR(x)
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 /*
  *      SMP has a few special interrupts for IPI messages
  */
 
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
 
 /*
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
  */
-extern char _stext[];
-
+extern char _stext;
 static inline void s390_do_profile (unsigned long addr)
 {
         if (prof_buffer && current->pid) {
@@ -828,10 +832,8 @@
 
 #define s390irq_spin_lock_irqsave(irq,flags) \
         spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
-
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
 #endif /* __KERNEL__ */
-
 #endif
 
diff -urN linux-2.2.18-pre20/include/asm-s390/lowcore.h linux/include/asm-s390/lowcore.h
--- linux-2.2.18-pre20/include/asm-s390/lowcore.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/lowcore.h	Mon Dec  3 22:14:18 2001
@@ -130,7 +130,7 @@
 	__u32        floating_pt_save_area[8]; /* 0x160 */
 	__u32        gpregs_save_area[16];     /* 0x180 */
         __u8         pad7[0x200-0x1c0];        /* 0x1c0 */
-	
+
         __u32        access_regs_save_area[16];/* 0x200 */
         __u32        cregs_save_area[16];      /* 0x240 */
         psw_t        return_psw;               /* 0x280 */
diff -urN linux-2.2.18-pre20/include/asm-s390/mathemu.h linux/include/asm-s390/mathemu.h
--- linux-2.2.18-pre20/include/asm-s390/mathemu.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/mathemu.h	Mon Dec  3 22:14:18 2001
@@ -12,12 +12,12 @@
 
 extern int math_emu_b3(__u8 *, struct pt_regs *);
 extern int math_emu_ed(__u8 *, struct pt_regs *);
-extern void math_emu_ldr(__u8 *);
-extern void math_emu_ler(__u8 *);
-extern void math_emu_std(__u8 *, struct pt_regs *);
-extern void math_emu_ld(__u8 *, struct pt_regs *);
-extern void math_emu_ste(__u8 *, struct pt_regs *);
-extern void math_emu_le(__u8 *, struct pt_regs *);
+extern int math_emu_ldr(__u8 *);
+extern int math_emu_ler(__u8 *);
+extern int math_emu_std(__u8 *, struct pt_regs *);
+extern int math_emu_ld(__u8 *, struct pt_regs *);
+extern int math_emu_ste(__u8 *, struct pt_regs *);
+extern int math_emu_le(__u8 *, struct pt_regs *);
 extern int math_emu_lfpc(__u8 *, struct pt_regs *);
 extern int math_emu_stfpc(__u8 *, struct pt_regs *);
 extern int math_emu_srnm(__u8 *, struct pt_regs *);
@@ -45,4 +45,7 @@
 extern __u64  __extendsfdf2(__u32);
 
 #endif                                 /* __MATHEMU__                      */
+
+
+
 
diff -urN linux-2.2.18-pre20/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- linux-2.2.18-pre20/include/asm-s390/pgtable.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/pgtable.h	Mon Dec  3 22:14:18 2001
@@ -33,7 +33,7 @@
 #define flush_cache_page(vma, vmaddr)           do { } while (0)
 #define flush_page_to_ram(page)                 do { } while (0)
 #define flush_icache_range(start, end)          do { } while (0)
-#define flush_dcache_page(page)			do { } while (0)
+#define flush_dcache_page(page)                 do { } while (0)
 
 /*
  * TLB flushing:
@@ -80,7 +80,7 @@
 }
 
 #if 0 /* Arggh, ipte doesn't work correctly !! */
-static inline void flush_tlb_page(struct vm_area_struct *vma,
+static inline void flush_tlb_page(struct vm_area_struct * vma,
         unsigned long va)
 {
         __flush_tlb_one(vma->vm_mm,va);
@@ -304,7 +304,7 @@
  * The Kernel segment-tables includes the User segment-table
  */
 
-#define _SEGMENT_TABLE  (_USER_SEG_TABLE_LEN|0x80000000)
+#define _SEGMENT_TABLE  (_USER_SEG_TABLE_LEN|0x80000000|0x100)
 #define _KERNSEG_TABLE  (_KERNEL_SEG_TABLE_LEN)
 
 /*
@@ -397,7 +397,7 @@
 
 #define SET_PAGE_DIR(tsk,pgdir)                                                 \
 do {                                                                            \
-        unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE; \
+        unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE;  \
         (tsk)->tss.user_seg = __pgdir;                                        \
         if ((tsk) == current) {                                               \
                 __asm__ __volatile__("lctl  7,7,%0": :"m" (__pgdir));         \
diff -urN linux-2.2.18-pre20/include/asm-s390/processor.h linux/include/asm-s390/processor.h
--- linux-2.2.18-pre20/include/asm-s390/processor.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/processor.h	Mon Dec  3 22:14:18 2001
@@ -90,7 +90,7 @@
 
 #define INIT_MMAP \
 { &init_mm, 0, 0, NULL, PAGE_SHARED, \
-VM_READ | VM_WRITE | VM_EXEC, 1, NULL, &init_mm.mmap }
+VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
 #define INIT_TSS  { (struct pt_regs *) 0,                         \
                     { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
diff -urN linux-2.2.18-pre20/include/asm-s390/ptrace.h linux/include/asm-s390/ptrace.h
--- linux-2.2.18-pre20/include/asm-s390/ptrace.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/ptrace.h	Mon Dec  3 22:14:18 2001
@@ -145,12 +145,8 @@
 #ifdef __KERNEL__
 #define user_mode(regs) ((regs)->psw.mask & PSW_PROBLEM_STATE)
 #define instruction_pointer(regs) ((regs)->psw.addr)
-
-struct thread_struct;
-extern int sprintf_regs(int line,char *buff,struct task_struct * task,
-			struct thread_struct *tss,struct pt_regs * regs);
-extern void show_regs(struct task_struct * task,struct thread_struct *tss,
-		      struct pt_regs * regs);
+extern void show_regs(struct pt_regs * regs);
+extern char *task_show_regs(struct task_struct *task, char *buffer);
 #endif
 
 
diff -urN linux-2.2.18-pre20/include/asm-s390/s390-regs-common.h linux/include/asm-s390/s390-regs-common.h
--- linux-2.2.18-pre20/include/asm-s390/s390-regs-common.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/s390-regs-common.h	Mon Dec  3 22:14:18 2001
@@ -69,10 +69,14 @@
 	freg_t  fprs[NUM_FPRS];              
 } s390_fp_regs;
 
-#define FPC_DXC_MASK            0x0000FF00
+
 #define FPC_EXCEPTION_MASK      0xF8000000
 #define FPC_FLAGS_MASK          0x00F80000
+#define FPC_DXC_MASK            0x0000FF00
 #define FPC_RM_MASK             0x00000003
+#define FPC_VALID_MASK         ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \
+                                 FPC_DXC_MASK|FPC_RM_MASK))
+
 
 
 /*
diff -urN linux-2.2.18-pre20/include/asm-s390/s390dyn.h linux/include/asm-s390/s390dyn.h
--- linux-2.2.18-pre20/include/asm-s390/s390dyn.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/s390dyn.h	Mon Dec  3 22:14:18 2001
@@ -3,7 +3,7 @@
  *   S/390 data definitions for dynamic device attachment
  *
  *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
diff -urN linux-2.2.18-pre20/include/asm-s390/s390io.h linux/include/asm-s390/s390io.h
--- linux-2.2.18-pre20/include/asm-s390/s390io.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/s390io.h	Mon Dec  3 22:14:18 2001
@@ -10,7 +10,7 @@
 #define __s390io_h
 
 /*
- * Private data structure used by do_IO()
+ * IRQ data structure used by I/O subroutines
  *
  * Note : If bit flags are added, the "unused" value must be
  *        decremented accordingly !
diff -urN linux-2.2.18-pre20/include/asm-s390/s390mach.h linux/include/asm-s390/s390mach.h
--- linux-2.2.18-pre20/include/asm-s390/s390mach.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/s390mach.h	Mon Dec  3 22:14:18 2001
@@ -3,8 +3,7 @@
  *   S/390 data definitions for machine check processing
  *
  *  S390 version
- *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- *                             IBM Corporation
+ *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
@@ -61,8 +60,8 @@
 #define CRW_ERC_PERRI    0x07 /* perm. error, facility init */
 #define CRW_ERC_PMOD     0x08 /* installed parameters modified */
 
-#define MAX_CRW_PENDING  100
-#define MAX_MACH_PENDING 100
+#define MAX_CRW_PENDING  1024
+#define MAX_MACH_PENDING 1024
 
 //
 // CRW Entry
diff -urN linux-2.2.18-pre20/include/asm-s390/sigcontext.h linux/include/asm-s390/sigcontext.h
--- linux-2.2.18-pre20/include/asm-s390/sigcontext.h	Wed May  3 17:16:51 2000
+++ linux/include/asm-s390/sigcontext.h	Mon Dec  3 22:14:18 2001
@@ -7,7 +7,10 @@
 
 #ifndef _ASM_S390_SIGCONTEXT_H
 #define _ASM_S390_SIGCONTEXT_H
-#include <asm/s390-regs-common.h>
+
+#define __NUM_GPRS 16
+#define __NUM_FPRS 16
+#define __NUM_ACRS 16
 
 /*
   Has to be at least _NSIG_WORDS from asm/signal.h
@@ -15,20 +18,39 @@
 #define _SIGCONTEXT_NSIG      64
 #define _SIGCONTEXT_NSIG_BPW  32
 /* Size of stack frame allocated when calling signal handler. */
-#define __SIGNAL_FRAMESIZE      STACK_FRAME_OVERHEAD
-#define _SIGCONTEXT_NSIG_WORDS  (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
-#define SIGMASK_COPY_SIZE       (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+#define __SIGNAL_FRAMESIZE	96
+#define _SIGCONTEXT_NSIG_WORDS	(_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
+#define _SIGMASK_COPY_SIZE	(sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+
+typedef struct 
+{
+        unsigned long mask;
+        unsigned long addr;
+} _psw_t __attribute__ ((aligned(8)));
+
+typedef struct
+{
+	_psw_t psw;
+	unsigned long gprs[__NUM_GPRS];
+	unsigned int  acrs[__NUM_ACRS];
+} _s390_regs_common __attribute__ ((packed));
+
+typedef struct
+{
+	unsigned int fpc;
+	double   fprs[__NUM_FPRS];
+} _s390_fp_regs;
 
 typedef struct
 {
-	s390_regs_common regs;
-	s390_fp_regs     fpregs;
-} sigregs;
+	_s390_regs_common regs;
+	_s390_fp_regs     fpregs;
+} _sigregs;
 
 struct sigcontext
 {
 	unsigned long	oldmask[_SIGCONTEXT_NSIG_WORDS];
-	sigregs         *sregs;
+	_sigregs        *sregs;
 };
 
 
diff -urN linux-2.2.18-pre20/include/asm-s390/sigp.h linux/include/asm-s390/sigp.h
--- linux-2.2.18-pre20/include/asm-s390/sigp.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/sigp.h	Mon Dec  3 22:14:18 2001
@@ -150,6 +150,7 @@
 	ec_get_ctl,
 	ec_set_ctl_masked,
         ec_ptlb,
+        ec_callback,
         ec_cmd_last
 } ec_cmd_sig;
 
@@ -187,6 +188,13 @@
 	__u32 andvals[16];
 } ec_creg_mask_parms;
 
+/* parameter area for the callback signal */
+typedef struct
+{
+  void (*callback)(void *);
+  void *data;
+} ec_callback_parms;
+
 /*
  * Signal processor
  */
@@ -249,6 +257,8 @@
 		);
    return ccode;
 }
+
+extern void smp_do_callback_all(void (*callback)(void *), void *data);
 
 #endif __SIGP__
 
diff -urN linux-2.2.18-pre20/include/asm-s390/spinlock.h linux/include/asm-s390/spinlock.h
--- linux-2.2.18-pre20/include/asm-s390/spinlock.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/spinlock.h	Mon Dec  3 22:14:18 2001
@@ -97,9 +97,9 @@
         __asm__ __volatile("    bras  1,1f\n"
                            "0:  diag  0,0,68\n"
                            "1:  slr   0,0\n"
-			   "    cs    0,1,%1\n"
+                           "    cs    0,1,%1\n"
                            "    jl    0b\n"
-			   : "=m" (lp->lock)
+                           : "=m" (lp->lock)
                            : "0" (lp->lock) : "0", "1", "cc" );
 }
 
diff -urN linux-2.2.18-pre20/include/asm-s390/system.h linux/include/asm-s390/system.h
--- linux-2.2.18-pre20/include/asm-s390/system.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/system.h	Mon Dec  3 22:14:18 2001
@@ -31,7 +31,7 @@
                         asm volatile (
                                 "   lhi   1,3\n"
                                 "   nr    1,%0\n"     /* isolate last 2 bits */
-                                "   xr    1,%0\n"     /* align ptr */
+                                "   xr    %0,1\n"     /* align ptr */
                                 "   bras  2,0f\n"
                                 "   icm   1,8,%1\n"   /* for ptr&3 == 0 */
                                 "   stcm  0,8,%1\n"
@@ -43,13 +43,13 @@
                                 "   stcm  0,1,%1\n"
                                 "0: sll   1,3\n"
                                 "   la    2,0(1,2)\n" /* r2 points to an icm */
-                                "   l     0,%1\n"     /* get fullword */
+                                "   l     0,0(%0)\n"  /* get fullword */
                                 "1: lr    1,0\n"      /* cs loop */
                                 "   ex    0,0(2)\n"   /* insert x */
-                                "   cs    0,1,%1\n"
+                                "   cs    0,1,0(%0)\n"
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
-                                : "+a&" (ptr) : "m" (x)
+                                : "+a&" (ptr), "+m" (x) :
                                 : "memory", "0", "1", "2");
                 case 2:
                         if(((__u32)ptr)&1)
@@ -57,7 +57,7 @@
                         asm volatile (
                                 "   lhi   1,2\n"
                                 "   nr    1,%0\n"     /* isolate bit 2^1 */
-                                "   xr    1,%0\n"     /* align ptr */
+                                "   xr    %0,1\n"     /* align ptr */
                                 "   bras  2,0f\n"
                                 "   icm   1,12,%1\n"   /* for ptr&2 == 0 */
                                 "   stcm  0,12,%1\n"
@@ -65,13 +65,13 @@
                                 "   stcm  0,3,%1\n"
                                 "0: sll   1,2\n"
                                 "   la    2,0(1,2)\n" /* r2 points to an icm */
-                                "   l     0,%1\n"     /* get fullword */
+                                "   l     0,0(%0)\n"  /* get fullword */
                                 "1: lr    1,0\n"      /* cs loop */
                                 "   ex    0,0(2)\n"   /* insert x */
-                                "   cs    0,1,%1\n"
+                                "   cs    0,1,0(%0)\n"
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
-                                : "+a&" (ptr) : "m" (x)
+                                : "+a&" (ptr), "+m" (x) :
                                 : "memory", "0", "1", "2");
                         break;
                 case 4:
@@ -198,7 +198,6 @@
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
-extern void show_crashed_task_info(void);
 #endif
 
 #define switch_to(prev,next,last) do {                                       \
diff -urN linux-2.2.18-pre20/include/asm-s390/termios.h linux/include/asm-s390/termios.h
--- linux-2.2.18-pre20/include/asm-s390/termios.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/termios.h	Mon Dec  3 22:14:18 2001
@@ -89,7 +89,7 @@
         get_user(tmp, &(termio)->c_lflag); \
         (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
         get_user((termios)->c_line, &(termio)->c_line); \
-	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+        copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
 })
 
 /*
diff -urN linux-2.2.18-pre20/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h
--- linux-2.2.18-pre20/include/asm-s390/uaccess.h	Mon Sep  4 10:39:28 2000
+++ linux/include/asm-s390/uaccess.h	Mon Dec  3 22:14:18 2001
@@ -203,80 +203,80 @@
 extern int __put_user_bad(void);
 
 
-#define __get_user_asm_4(x, ptr, err)                                   \
-({                                                                      \
-        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
-                                "   la    4,%2\n"                       \
-                                "   sacf  512\n"                        \
-                                "0: l     %0,0(4)\n"                    \
-                                "   sacf  0\n"                          \
-                                "1:\n"                                  \
-                                ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0\n"                          \
-                                "   lhi   %1,%h3\n"                     \
-                                "   bras  4,3f\n"                       \
-                                "   .long 1b\n"                         \
-                                "3: l     4,0(4)\n"                     \
-                                "   br    4\n"                          \
-                                ".previous\n"                           \
-                                ".section __ex_table,\"a\"\n"           \
-                                "   .align 4\n"                         \
-                                "   .long 0b,2b\n"                      \
-                                ".previous"                             \
-                                : "=d" (x) , "=&d" (err)                \
-                                : "m" (*(__u32*) ptr), "K" (-EFAULT)    \
-                                : "4" );                                \
+#define __get_user_asm_4(x, ptr, err)                                      \
+({                                                                         \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
+                                "   la    4,%2\n"                          \
+                                "   sacf  512\n"                           \
+                                "0: l     %0,0(4)\n"                       \
+                                "   sacf  0\n"                             \
+                                "1:\n"                                     \
+                                ".section .fixup,\"ax\"\n"                 \
+                                "2: sacf  0\n"                             \
+                                "   lhi   %1,%h3\n"                        \
+                                "   bras  4,3f\n"                          \
+                                "   .long 1b\n"                            \
+                                "3: l     4,0(4)\n"                        \
+                                "   br    4\n"                             \
+                                ".previous\n"                              \
+                                ".section __ex_table,\"a\"\n"              \
+                                "   .align 4\n"                            \
+                                "   .long 0b,2b\n"                         \
+                                ".previous"                                \
+                                : "=d" (x) , "=&d" (err)                   \
+                                : "m" (*(const __u32*) ptr), "K" (-EFAULT) \
+                                : "4" );                                   \
 })
 
-#define __get_user_asm_2(x, ptr, err)                                   \
-({                                                                      \
-        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
-                                "   la    4,%2\n"                       \
-                                "   sacf  512\n"                        \
-                                "0: lh    %0,0(4)\n"                    \
-                                "   sacf  0\n"                          \
-                                "1:\n"                                  \
-                                ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0\n"                          \
-                                "   lhi   %1,%h3\n"                     \
-                                "   bras  4,3f\n"                       \
-                                "   .long 1b\n"                         \
-                                "3: l     4,0(4)\n"                     \
-                                "   br    4\n"                          \
-                                ".previous\n"                           \
-                                ".section __ex_table,\"a\"\n"           \
-                                "   .align 4\n"                         \
-                                "   .long 0b,2b\n"                      \
-                                ".previous"                             \
-                                : "=d" (x) , "=&d" (err)                \
-                                : "m" (*(__u16*) ptr), "K" (-EFAULT)    \
-                                : "4" );                                \
+#define __get_user_asm_2(x, ptr, err)                                      \
+({                                                                         \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
+                                "   la    4,%2\n"                          \
+                                "   sacf  512\n"                           \
+                                "0: lh    %0,0(4)\n"                       \
+                                "   sacf  0\n"                             \
+                                "1:\n"                                     \
+                                ".section .fixup,\"ax\"\n"                 \
+                                "2: sacf  0\n"                             \
+                                "   lhi   %1,%h3\n"                        \
+                                "   bras  4,3f\n"                          \
+                                "   .long 1b\n"                            \
+                                "3: l     4,0(4)\n"                        \
+                                "   br    4\n"                             \
+                                ".previous\n"                              \
+                                ".section __ex_table,\"a\"\n"              \
+                                "   .align 4\n"                            \
+                                "   .long 0b,2b\n"                         \
+                                ".previous"                                \
+                                : "=d" (x) , "=&d" (err)                   \
+                                : "m" (*(const __u16*) ptr), "K" (-EFAULT) \
+                                : "4" );                                   \
 })
 
-#define __get_user_asm_1(x, ptr, err)                                   \
-({                                                                      \
-        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
-                                "   la    4,%2\n"                       \
-                                "   sr    %0,%0\n"                      \
-                                "   sacf  512\n"                        \
-                                "0: ic    %0,0(4)\n"                    \
-                                "   sacf  0\n"                          \
-                                "1:\n"                                  \
-                                ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0\n"                          \
-                                "   lhi   %1,%h3\n"                     \
-                                "   bras  4,3f\n"                       \
-                                "   .long 1b\n"                         \
-                                "3: l     4,0(4)\n"                     \
-                                "   br    4\n"                          \
-                                ".previous\n"                           \
-                                ".section __ex_table,\"a\"\n"           \
-                                "   .align 4\n"                         \
-                                "   .long 0b,2b\n"                      \
-                                ".previous"                             \
-                                : "=d" (x) , "=&d" (err)                \
-                                : "m" (*(__u8*) ptr), "K" (-EFAULT)     \
-                                : "4" );                                \
+#define __get_user_asm_1(x, ptr, err)                                     \
+({                                                                        \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                        \
+                                "   la    4,%2\n"                         \
+                                "   sr    %0,%0\n"                        \
+                                "   sacf  512\n"                          \
+                                "0: ic    %0,0(4)\n"                      \
+                                "   sacf  0\n"                            \
+                                "1:\n"                                    \
+                                ".section .fixup,\"ax\"\n"                \
+                                "2: sacf  0\n"                            \
+                                "   lhi   %1,%h3\n"                       \
+                                "   bras  4,3f\n"                         \
+                                "   .long 1b\n"                           \
+                                "3: l     4,0(4)\n"                       \
+                                "   br    4\n"                            \
+                                ".previous\n"                             \
+                                ".section __ex_table,\"a\"\n"             \
+                                "   .align 4\n"                           \
+                                "   .long 0b,2b\n"                        \
+                                ".previous"                               \
+                                : "=d" (x) , "=&d" (err)                  \
+                                : "m" (*(const __u8*) ptr), "K" (-EFAULT) \
+                                : "4" );                                  \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -332,13 +332,19 @@
 extern int __get_user_bad(void);
 
 /*
+ * These two fixup routines have a special linkage. Not to be
+ * called directly.
+ */
+extern void __copy_from_user_fixup(void);
+extern void __copy_to_user_fixup(void);
+
+/*
  * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel)
  */
 
 extern inline unsigned long
 __copy_to_user_asm(void* to, const void* from,  long n)
 {
-
         __asm__ __volatile__ (  "   lr    2,%2\n"
                                 "   lr    4,%1\n"
                                 "   lr    3,%0\n"
@@ -348,23 +354,12 @@
                                 "   jo    0b\n"
                                 "   sacf  0\n"
                                 "1: lr    %0,3\n"
-                                ".section .fixup,\"ax\"\n"
-                                "2: lhi   5,-4096\n"
-                                "   n     5,0x90\n"
-                                "   sr    5,4\n"
-                                "   mvcle 4,2,0\n"
-                                "   sacf  0\n"
-                                "   basr  4,0\n"
-                                "   l     4,3f-.(4)\n"
-                                "   br    4\n"
-                                "3: .long 1b\n"
-                                ".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 4\n"
-				"   .long  0b,2b\n"
+				"   .long  0b,__copy_to_user_fixup\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "2", "3", "4", "5" );
+                                : "1", "2", "3", "4", "5" );
         return n;
 }
 
@@ -397,23 +392,12 @@
                                 "   jo    0b\n"
                                 "   sacf  0\n"
                                 "1: lr    %0,5\n"
-                                ".section .fixup,\"ax\"\n"
-                                "2: lhi   3,-4096\n"
-                                "   n     3,0x90\n"
-                                "   sr    3,4\n"
-                                "   mvcle 2,4,0\n"
-                                "   sacf  0\n"
-                                "   basr  4,0\n"
-                                "   l     4,3f-.(4)\n"
-                                "   br    4\n"
-                                "3: .long 1b\n"
-                                ".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 4\n"
-				"   .long  0b,2b\n"
+				"   .long  0b,__copy_from_user_fixup\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "2", "3", "4", "5" );
+                                : "1", "2", "3", "4", "5" );
         return n;
 }
 
@@ -443,7 +427,7 @@
  */
 
 static inline long
-strncpy_from_user(char *dst, const char *src, long count)
+__strncpy_from_user(char *dst, const char *src, long count)
 {
         long len;
         __asm__ __volatile__ (  "   slr   %0,%0\n"
@@ -463,7 +447,7 @@
                                 "3: lhi   %0,%h4\n"
 				"   basr  3,0\n"
                                 "   l     3,4f-.(3)\n"
-				"   br    3\n"
+                                "   br    3\n"
 				"4: .long 2b\n"
 				".previous\n"
 				".section __ex_table,\"a\"\n"
@@ -472,12 +456,21 @@
                                 "   .long  1b,3b\n"
 				".previous"
                                 : "=&a" (len)
-                                : "a"  (dst), "d" (src), "d" (count),
+                                : "a" (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
                                 : "2", "3", "4", "memory" );
         return len;
 }
 
+static inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+        long res = -EFAULT;
+        if (access_ok(VERIFY_READ, src, 1))
+                res = __strncpy_from_user(dst, src, count);
+        return res;
+}
+
 /*
  * Return the size of a string (including the ending 0)
  *
@@ -519,7 +512,7 @@
  */
 
 static inline unsigned long
-clear_user(void *to, unsigned long n)
+__clear_user(void *to, unsigned long n)
 {
         __asm__ __volatile__ (  "   sacf  512\n"
                                 "   lr    4,%1\n"
@@ -530,24 +523,21 @@
                                 "   jo    0b\n"
                                 "   sacf  0\n"
                                 "1: lr    %0,3\n"
-                                ".section .fixup,\"ax\"\n"
-                                "2: lhi   5,-4096\n"
-                                "   n     5,0x90\n"
-                                "   sr    5,4\n"
-                                "   mvcle 4,2,0\n"
-                                "   sacf  0\n"
-                                "   basr  4,0\n"
-                                "   l     4,3f-.(4)\n"
-                                "   br    4\n"
-                                "3: .long 1b\n"
-                                ".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 4\n"
-				"   .long  0b,2b\n"
+				"   .long  0b,__copy_to_user_fixup\n"
 				".previous"
                                 : "+&a" (n)
                                 : "a"   (to)
-                                : "cc", "2", "3", "4", "5" );
+                                : "cc", "1", "2", "3", "4", "5" );
+        return n;
+}
+
+static inline unsigned long
+clear_user(void *to, unsigned long n)
+{
+        if (access_ok(VERIFY_WRITE, to, n))
+                n = __clear_user(to, n);
         return n;
 }
 
diff -urN linux-2.2.18-pre20/include/asm-s390/unistd.h linux/include/asm-s390/unistd.h
--- linux-2.2.18-pre20/include/asm-s390/unistd.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/unistd.h	Mon Dec  3 22:14:18 2001
@@ -191,7 +191,7 @@
         return (type) (res);                                 \
 } while (0)
 
-#define _svc_clobber "cc", "memory"
+#define _svc_clobber "2", "cc", "memory"
 
 #define _syscall0(type,name)                                 \
 type name(void) {                                            \
diff -urN linux-2.2.18-pre20/include/asm-sparc64/envctrl.h linux/include/asm-sparc64/envctrl.h
--- linux-2.2.18-pre20/include/asm-sparc64/envctrl.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-sparc64/envctrl.h	Mon Dec  3 22:14:18 2001
@@ -1,4 +1,4 @@
-/* $Id: envctrl.h,v 1.1.2.1 2000/05/02 04:23:33 davem Exp $
+/* $Id: envctrl.h,v 1.1.2.2 2000/11/08 09:43:04 davem Exp $
  *
  * envctrl.h: Definitions for access to the i2c environment
  *            monitoring on Ultrasparc systems.
@@ -53,6 +53,7 @@
 #define ENVCTRL_RD_SCSI_TEMPERATURE	_IOR('p', 0x46, int)
 #define ENVCTRL_RD_ETHERNET_TEMPERATURE	_IOR('p', 0x47, int)
 #define ENVCTRL_RD_MTHRBD_TEMPERATURE	_IOR('p', 0x48, int)
+#define ENVCTRL_RD_GLOBALADDRESS	_IOR('p', 0x49, int)
 
 /* Read return values for a voltage status request. */
 #define ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD	0x01
diff -urN linux-2.2.18-pre20/include/linux/genhd.h linux/include/linux/genhd.h
--- linux-2.2.18-pre20/include/linux/genhd.h	Tue Jan  4 10:12:24 2000
+++ linux/include/linux/genhd.h	Mon Dec  3 22:14:18 2001
@@ -256,6 +256,18 @@
 
 extern struct gendisk *gendisk_head;	/* linked list of disks */
 
+#ifdef CONFIG_ARCH_S390
+/*
+ * dasd_device_name(...)
+ * formats the devicename of the indicated disk
+ * into the supplied buffer, and returns a pointer
+ * to that same buffer (for convenience).
+ * Because the S390 DASDs span a larger namespace than other
+ * platforms we need our own function.
+ */
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*); 
+#endif
+
 /*
  * disk_name() is used by genhd.c and md.c.
  * It formats the devicename of the indicated disk
diff -urN linux-2.2.18-pre20/include/linux/input.h linux/include/linux/input.h
--- linux-2.2.18-pre20/include/linux/input.h	Mon Dec  3 22:14:09 2001
+++ linux/include/linux/input.h	Mon Dec  3 22:14:18 2001
@@ -210,7 +210,7 @@
 #define KEY_F22			121		
 #define KEY_F23			122		
 #define KEY_F24			123		
-#define KEY_JPN			124		
+#define KEY_KPCOMMA		124
 #define KEY_LEFTMETA		125		
 #define KEY_RIGHTMETA		126		
 #define KEY_COMPOSE		127		
@@ -266,8 +266,29 @@
 #define KEY_EDIT		176
 #define KEY_SCROLLUP		177
 #define KEY_SCROLLDOWN		178
+#define KEY_KPLEFTPAREN		179
+#define KEY_KPRIGHTPAREN	180
 
-#define KEY_UNKNOWN		180
+#define KEY_INTL1		181
+#define KEY_INTL2		182
+#define KEY_INTL3		183
+#define KEY_INTL4		184
+#define KEY_INTL5		185
+#define KEY_INTL6		186
+#define KEY_INTL7		187
+#define KEY_INTL8		188
+#define KEY_INTL9		189
+#define KEY_LANG1		190
+#define KEY_LANG2		191
+#define KEY_LANG3		192
+#define KEY_LANG4		193
+#define KEY_LANG5		194
+#define KEY_LANG6		195
+#define KEY_LANG7		196
+#define KEY_LANG8		197
+#define KEY_LANG9		198
+
+#define KEY_UNKNOWN		200
 
 #define BTN_MISC		0x100
 #define BTN_0			0x100
@@ -423,6 +444,7 @@
 #define BUS_GAMEPORT		0x14
 #define BUS_PARPORT		0x15
 #define BUS_AMIGA		0x16
+#define BUS_ADB			0x17
 
 #ifdef __KERNEL__
 
diff -urN linux-2.2.18-pre20/include/linux/openpic.h linux/include/linux/openpic.h
--- linux-2.2.18-pre20/include/linux/openpic.h	Mon Sep  4 10:39:28 2000
+++ linux/include/linux/openpic.h	Mon Dec  3 22:14:18 2001
@@ -356,6 +356,7 @@
 /* Interrupt Sources */
 extern void openpic_enable_irq(u_int irq);
 extern void openpic_disable_irq(u_int irq);
+extern u_int openpic_get_enable(u_int irq);
 extern void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
 			    int is_level);
 extern void openpic_mapirq(u_int irq, u_int cpumask);
diff -urN linux-2.2.18-pre20/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.2.18-pre20/include/linux/pci.h	Mon Dec  3 22:14:09 2001
+++ linux/include/linux/pci.h	Mon Dec  3 22:14:18 2001
@@ -190,6 +190,27 @@
 #define  PCI_CAP_ID_AGP		0x02	/* Accelerated Graphics Port */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 
+/* Power Management Registers */
+
+#define  PCI_PM_CAP_VER_MASK	0x0007	/* Version */
+#define  PCI_PM_CAP_PME_CLOCK	0x0008	/* PME clock required */
+#define  PCI_PM_CAP_AUX_POWER	0x0010	/* Auxilliary power support */
+#define  PCI_PM_CAP_DSI		0x0020	/* Device specific initialization */
+#define  PCI_PM_CAP_D1		0x0200	/* D1 power state support */
+#define  PCI_PM_CAP_D2		0x0400	/* D2 power state support */
+#define  PCI_PM_CAP_PME		0x0800	/* PME pin supported */
+#define PCI_PM_CTRL		4	/* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK	0x0003	/* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_PME_ENABLE	0x0100	/* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK	0x1e00	/* Data select (??) */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK	0x6000	/* Data scale (??) */
+#define  PCI_PM_CTRL_PME_STATUS	0x8000	/* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS	6	/* PPB support extensions (??) */
+#define  PCI_PM_PPB_B2_B3	0x40	/* Stop clock when in D3hot (??) */
+#define  PCI_PM_BPCC_ENABLE	0x80	/* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER	7	/* (??) */
+#define PCI_PM_SIZEOF		8
+
 /* Device classes and subclasses */
 
 #define PCI_CLASS_NOT_DEFINED		0x0000
diff -urN linux-2.2.18-pre20/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux-2.2.18-pre20/include/linux/sysctl.h	Mon Dec  3 22:14:09 2001
+++ linux/include/linux/sysctl.h	Mon Dec  3 22:14:18 2001
@@ -107,6 +107,7 @@
 	KERN_SHMALL=41,		/* int: maximum size of shared memory */
 	KERN_SPARC_STOP_A=44,	/* int: Sparc Stop-A enable */
 	KERN_HOTPLUG=49,	/* string: path to hotplug policy agent */
+	KERN_IEEE_EMULATION_WARNINGS=50 /* int: unimplemented ieee instructions */
 };
 
 
@@ -433,7 +434,8 @@
 /* CTL_DEV names: */
 enum {
 	DEV_CDROM=1,
-	DEV_HWMON=2
+	DEV_HWMON=2,
+	DEV_MAC_HID=3
 };
 
 /* /proc/sys/dev/cdrom */
@@ -444,6 +446,16 @@
 	DEV_CDROM_DEBUG=4,
 	DEV_CDROM_LOCK=5,
 	DEV_CDROM_CHECK_MEDIA=6
+};
+
+/* /proc/sys/dev/mac_hid */
+enum {
+	DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES=1,
+	DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES=2,
+	DEV_MAC_HID_MOUSE_BUTTON_EMULATION=3,
+	DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE=4,
+	DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE=5,
+	DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6
 };
 
 #ifdef __KERNEL__
diff -urN linux-2.2.18-pre20/init/main.c linux/init/main.c
--- linux-2.2.18-pre20/init/main.c	Mon Dec  3 22:14:09 2001
+++ linux/init/main.c	Mon Dec  3 22:14:18 2001
@@ -27,6 +27,10 @@
 #include <asm/io.h>
 #include <asm/bugs.h>
 
+#ifdef CONFIG_ARCH_S390
+#include <asm/s390mach.h>
+#endif
+
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
@@ -1536,6 +1540,10 @@
 	 * Ok, at this point all CPU's should be initialized, so
 	 * we can start looking into devices..
 	 */
+#ifdef CONFIG_ARCH_S390
+	s390_init_machine_check();
+#endif
+
 #ifdef CONFIG_PCI
 	pci_init();
 #endif
diff -urN linux-2.2.18-pre20/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.2.18-pre20/kernel/sysctl.c	Mon Dec  3 22:14:09 2001
+++ linux/kernel/sysctl.c	Mon Dec  3 22:14:18 2001
@@ -58,6 +58,13 @@
 extern char reboot_command [];
 extern int stop_a_enabled;
 #endif
+
+#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_IEEEFPU_EMULATION
+extern int sysctl_ieee_emulation_warnings;
+#endif
+#endif
+
 #ifdef __powerpc__
 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
@@ -237,7 +244,13 @@
 #ifdef CONFIG_MAGIC_SYSRQ
 	{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
 	 0644, NULL, &proc_dointvec},
-#endif	 
+#endif
+#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_IEEEFPU_EMULATION
+	{KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
+	 &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
+#endif
+#endif 
 	{0}
 };
 
diff -urN linux-2.2.18-pre20/scripts/Lindent linux/scripts/Lindent
--- linux-2.2.18-pre20/scripts/Lindent	Wed Dec 31 16:00:00 1969
+++ linux/scripts/Lindent	Mon Dec  3 22:14:18 2001
@@ -0,0 +1,2 @@
+#!/bin/bash
+indent -kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di0 -nbc -lp -psl $@
