]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.18pre21 2.2.18pre21
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:22:47 +0000 (15:22 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:22:47 +0000 (15:22 -0500)
o Environment controller update for sparc (Eric Brower)
o No italian translation for config.help (Andrea Ferraris)
o Fix type error in buz driver (Pete Zaitcev)
o Resnchronize Apple PowerMac codebase (Paul Mackerras & co)
o Merge powermac tree fixes into usb
o Powermac input device handling changes
o Fix console switch fonts
o S/390 merge (IBM S/390 folks)
(Merge grunt work done by Kurt Roeckx)
o Make knfsd TCP an option  (Alan Cox)
o Drop cisco info packets (0x2000) (Ivan Passos)
o Add belkin USB serial cable (William Greathouse)

202 files changed:
CREDITS
Documentation/Configure.help
Documentation/s390/xpram.txt [new file with mode: 0644]
Documentation/usb/usb-serial.txt
Makefile
arch/i386/kernel/smp.c
arch/ppc/boot/Makefile
arch/ppc/boot/vreset.c
arch/ppc/coffboot/Makefile
arch/ppc/coffboot/chrpmain.c
arch/ppc/config.in
arch/ppc/kernel/Makefile
arch/ppc/kernel/apus_setup.c
arch/ppc/kernel/chrp_pci.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/chrp_time.c
arch/ppc/kernel/feature.c
arch/ppc/kernel/gemini_setup.c
arch/ppc/kernel/head.S
arch/ppc/kernel/irq.c
arch/ppc/kernel/mbx_pci.c
arch/ppc/kernel/mbx_setup.c
arch/ppc/kernel/misc.S
arch/ppc/kernel/open_pic.c
arch/ppc/kernel/open_pic.h
arch/ppc/kernel/openpic.c
arch/ppc/kernel/pci.c
arch/ppc/kernel/pmac_pci.c
arch/ppc/kernel/pmac_pic.c
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/pmac_support.c
arch/ppc/kernel/pmac_time.c
arch/ppc/kernel/ppc_htab.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/prep_pci.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/process.c
arch/ppc/kernel/prom.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/signal.c
arch/ppc/kernel/sleep.S
arch/ppc/kernel/smp.c
arch/ppc/kernel/syscalls.c
arch/ppc/kernel/time.c
arch/ppc/kernel/traps.c
arch/ppc/mm/extable.c
arch/ppc/mm/init.c
arch/ppc/xmon/start.c
arch/ppc/xmon/xmon.c
arch/s390/boot/ipleckd.S
arch/s390/config.in
arch/s390/defconfig
arch/s390/kernel/cpcmd.c
arch/s390/kernel/debug.c
arch/s390/kernel/entry.S
arch/s390/kernel/head.S
arch/s390/kernel/irq.c
arch/s390/kernel/mathemu.c
arch/s390/kernel/process.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/s390_ext.c
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/s390dyn.c
arch/s390/kernel/s390fpu.c
arch/s390/kernel/s390io.c
arch/s390/kernel/s390mach.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/traps.c
arch/s390/lib/Makefile
arch/s390/lib/delay.c
arch/s390/lib/uaccess.S [new file with mode: 0644]
arch/s390/mm/fault.c
arch/s390/mm/init.c
arch/s390/tools/dasdfmt/dasdfmt.8
arch/s390/tools/dasdfmt/dasdfmt.c
arch/s390/tools/hwc/Makefile [new file with mode: 0644]
arch/s390/tools/hwc/hwc_cntl_key.c [new file with mode: 0644]
arch/s390/tools/hwc/hwc_measure.c [new file with mode: 0644]
arch/s390/tools/hwc_cntl_key/Makefile [deleted file]
arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c [deleted file]
arch/s390/tools/silo/silo.c
arch/sparc64/kernel/ioctl32.c
drivers/Makefile
drivers/block/Config.in
drivers/block/genhd.c
drivers/block/ide-pmac.c
drivers/block/rd.c
drivers/char/Config.in
drivers/char/buz.c
drivers/char/console.c
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/misc.c
drivers/char/tty_io.c
drivers/macintosh/Makefile
drivers/macintosh/adb.c
drivers/macintosh/adbhid.c [new file with mode: 0644]
drivers/macintosh/mac_hid.c [new file with mode: 0644]
drivers/macintosh/mac_keyb.c
drivers/macintosh/macserial.c
drivers/macintosh/macserial.h
drivers/macintosh/mediabay.c
drivers/macintosh/nvram.c
drivers/macintosh/via-pmu.c
drivers/net/bmac.c
drivers/net/de4x5.c
drivers/net/gmac.c
drivers/net/gmac.h
drivers/net/hdlc.c
drivers/s390/Config.in
drivers/s390/Makefile
drivers/s390/block/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd.h
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/xpram.c
drivers/s390/ccwcache.c
drivers/s390/char/con3215.c
drivers/s390/char/hwc.h
drivers/s390/char/hwc_con.c
drivers/s390/char/hwc_rw.c
drivers/s390/char/hwc_rw.h
drivers/s390/char/hwc_tty.c
drivers/s390/idals.c [new file with mode: 0644]
drivers/s390/net/Makefile
drivers/s390/net/ctc.c
drivers/s390/net/iucv.c
drivers/sbus/char/envctrl.c
drivers/sound/awacs_defs.h
drivers/sound/dmasound.c
drivers/usb/Config.in
drivers/usb/keybdev.c
drivers/usb/serial/Makefile
drivers/usb/serial/belkin_sa.c [new file with mode: 0644]
drivers/usb/serial/belkin_sa.h [new file with mode: 0644]
drivers/usb/usb-ohci.c
drivers/usb/usb-ohci.h
drivers/video/aty128.h
drivers/video/aty128fb.c
drivers/video/atyfb.c
drivers/video/chipsfb.c
drivers/video/offb.c
fs/Config.in
fs/nfsd/nfssvc.c
fs/proc/array.c
include/asm-ppc/backlight.h [new file with mode: 0644]
include/asm-ppc/delay.h
include/asm-ppc/dma.h
include/asm-ppc/feature.h
include/asm-ppc/heathrow.h
include/asm-ppc/irq.h
include/asm-ppc/keyboard.h
include/asm-ppc/keylargo.h [new file with mode: 0644]
include/asm-ppc/machdep.h
include/asm-ppc/nvram.h
include/asm-ppc/pci-bridge.h
include/asm-ppc/pci.h [new file with mode: 0644]
include/asm-ppc/pmu.h
include/asm-ppc/processor.h
include/asm-ppc/system.h
include/asm-ppc/uaccess.h
include/asm-ppc/ucontext.h
include/asm-ppc/uninorth.h [new file with mode: 0644]
include/asm-ppc/unistd.h
include/asm-s390/atomic.h
include/asm-s390/bitops.h
include/asm-s390/ccwcache.h
include/asm-s390/checksum.h
include/asm-s390/dasd.h
include/asm-s390/debug.h
include/asm-s390/idals.h [new file with mode: 0644]
include/asm-s390/irq.h
include/asm-s390/lowcore.h
include/asm-s390/mathemu.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/ptrace.h
include/asm-s390/s390-regs-common.h
include/asm-s390/s390dyn.h
include/asm-s390/s390io.h
include/asm-s390/s390mach.h
include/asm-s390/sigcontext.h
include/asm-s390/sigp.h
include/asm-s390/spinlock.h
include/asm-s390/system.h
include/asm-s390/termios.h
include/asm-s390/uaccess.h
include/asm-s390/unistd.h
include/asm-sparc64/envctrl.h
include/linux/genhd.h
include/linux/input.h
include/linux/openpic.h
include/linux/pci.h
include/linux/sysctl.h
init/main.c
kernel/sysctl.c
scripts/Lindent [new file with mode: 0644]

diff --git a/CREDITS b/CREDITS
index 285986308b3cfcedf983d08f53234161143d2419..54b012ba7ea12031d7fbc95b6cf37c133d621c86 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -763,6 +763,15 @@ S: 8124 Constitution Apt. 7
 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
index 88eb5d379d92f978eba57e3f4a9c9cc765e386cf..042c3726d85cf649f014d5310ab40a99b12271bb 100644 (file)
@@ -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 @@ CONFIG_DISPLAY7SEG
 #
 # 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 --git a/Documentation/s390/xpram.txt b/Documentation/s390/xpram.txt
new file mode 100644 (file)
index 0000000..8693be4
--- /dev/null
@@ -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
index 4ffe021a7404bc575607df7409ea157ef1d87c7f..a6efeefa57d14d890ca3eb0bae2687d85506f175 100644 (file)
@@ -151,6 +151,37 @@ Digi AccelePort Driver
   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
index b84d817a14923efb3add9f67dee185cde818700e..2e646ce411b98dc10ac41ca2858f9985c5737299 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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 @@ ifeq ($(CONFIG_NET_FC),y)
 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
index cbc09a5a5972196d7e71d6a793406b4a78fb90ac..004ada11f9fb565a03c8f4ada74431e3f28f1d9b 100644 (file)
@@ -364,13 +364,20 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
                                        (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);
@@ -408,6 +415,12 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
                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;
+       }
        return num_processors;
 }
 
index 7152bace7c4410c9cc07d8e3a4c4a8f6fb417357..5febfc31cea13ec1330e93557a6d02809107b604 100644 (file)
@@ -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:
index c01361dc672184c98a35cb0c40365edd4345b296..bd44cd9d71e442649d728c821a42a84ee33148b5 100644 (file)
@@ -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  
  */
index 68b1255c63e60f41f9dcc23bfe172adb7546c11a..ad0389d3c2563b638b4d453fd3451c070cfb8987 100644 (file)
@@ -7,11 +7,11 @@ HOSTCFLAGS = -O -I$(TOPDIR)/include
 
 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 @@ else
 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
 
index 254ced627768fc2449e742f830594b0bda5b5457..b1f09efdd8d6a13c09134b16036c715207ca27d5 100644 (file)
@@ -18,13 +18,18 @@ void stop_imac_usb(void);
 #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 @@ boot(int a1, int a2, void *prom)
     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 @@ boot(int a1, int a2, void *prom)
     pause();
 }
 
+#if 0
 #define eieio()        asm volatile("eieio");
 
 void stop_imac_ethernet(void)
@@ -134,14 +145,35 @@ void stop_imac_usb(void)
     *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 *zalloc(void *x, unsigned items, unsigned size)
 
 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
index 6510dce98ef3ecc2dc074a6ff22648c7b4bc5fc4..a1a3313cda31e4b1bae033c1eb65d2e31188dba5 100644 (file)
@@ -26,12 +26,12 @@ if [ "$CONFIG_6xx" = "y" ]; then
   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 @@ fi
 
 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 @@ endmenu
 
 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'
@@ -194,6 +205,8 @@ fi
 
 endmenu
 
+source fs/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
index 9ea51146dd1a1d99454dc8bbfa00c59aa2f3b77a..10dba8913479c4581621521b9d64ac618fb754c2 100644 (file)
@@ -36,20 +36,40 @@ endif
 
 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 @@ find_name : find_name.c
        $(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
index bcefcc7cea67fe7514d3cba023615261e610e3ae..26db64271cb94c5eedbde46e7da401be041a7ae5 100644 (file)
@@ -624,7 +624,7 @@ apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
        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;
index 771c51364fd7de0cf2b488cf99952deb64c32d18..4f21f09989a363ac5866f4a75b038ab13ad11407 100644 (file)
@@ -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 @@ chrp_pcibios_fixup(void)
        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 )
                {
index 8d0630ffe62ace96bfd49082bf33efe1cb63441a..8e378a792cdb037e8a3dfaa43638f0084df75032 100644 (file)
@@ -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 @@ unsigned long chrp_get_rtc_time(void);
 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 @@ kdev_t boot_dev;
 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 @@ chrp_irq_cannonicalize(u_int irq)
        }
 }
 
-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 @@ __initfunc(void
                        (*(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 @@ __initfunc(void
                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 @@ __initfunc(void
                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 @@ __initfunc(void
                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 @@ __initfunc(void
        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 @@ __initfunc(void
        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;
 
index 2b7d9a23047d232bdb1368e88c947db0ba2d5385..03146756cb604ebf0fa038b9c267eeb9d500e19b 100644 (file)
@@ -31,18 +31,19 @@ static int nvram_as1 = NVRAM_AS1;
 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)
index 04bb15fe8bc9ed5a2db8190cd5a7a815e7433e4b..8f2771b717254dbc28c7533567a9beaab32cda89 100644 (file)
@@ -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>
 #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,12 +80,47 @@ static fbit feature_bits_ohare_pbook[] = {
        {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 */
@@ -101,15 +147,17 @@ static fbit feature_bits_heathrow[] = {
        {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 @@ static fbit feature_bits_paddington[] = {
        {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 @@ struct feature_controller {
 };
 
 /* 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 @@ feature_init(void)
                }
        }
 
+       /* 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 @@ feature_init(void)
 #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 @@ feature_add_controller(struct device_node *controller_device, fbit* bits)
        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 @@ feature_add_controller(struct device_node *controller_device, fbit* bits)
        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*
@@ -385,3 +516,369 @@ feature_test(struct device_node* device, enum system_feature f)
        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);
+}
+
index 79b6764db8f486a9b4ad0b4095103abec5d37530..ded9e28d8bac87dd25a8a6fcf5ff60ef40b4a70a 100644 (file)
@@ -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 @@ gemini_get_clock_speed(void)
        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 @@ void __init gemini_init_l2(void)
                        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 @@ void __init gemini_init_IRQ(void)
 #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 @@ void __init gemini_time_init(void)
                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 @@ void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5,
        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
 }
index e7941839099d56462f52c1aeeb1030154a30a45b..f379077776c60853e0436b778ba4c302926c0079 100644 (file)
  *  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 @@ __start:
 __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 @@ __secondary_start:
 #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 @@ label:                                              \
 #endif /* CONFIG_GEMINI */
 #else
        STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif 
+#endif
 
 /* Machine check */
        STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -1383,11 +1345,7 @@ hash_page:
        /* 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_slot:
  */
 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 @@ giveup_altivec:
        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 @@ copy_and_flush:
        . = 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 @@ start_here:
        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 @@ DoSyscall:
 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 @@ syscall_ret_1:
 /* 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 @@ m8xx_gorom:
        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 @@ flush_tlbs:
        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
+
+
index f63000cb55f2ce383b8934aae7a784226e0f2af9..a85a0a0ca88dd66be7e0c3922ef0b2eb46beb042 100644 (file)
@@ -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 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        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 @@ int get_irq_list(char *buf)
        }
 #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_irq_count;
 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 @@ static void show(char * str)
               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 @@ static void show(char * str)
                        printk("<[%08lx]> ", x);
                }
        }
+#endif
 }
 
 static inline void wait_on_bh(void)
index 5114c3cfb8332c7c45fb56edbbdde04fc2d10637..965ff65cce41b0d81624341ed5769fc039f3000b 100644 (file)
@@ -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
index d4f3c85fce96a30c6413193be5df6d9c25f1be72..b8daf85d54f207fb8d281e255c30ea6713817dfe 100644 (file)
 #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 @@ mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
        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)
index 5ec8b36d985e84b8927b0364ad23777647b544b5..72fe9c71996f432eb115a7ad8dafbcb0923114ff 100644 (file)
@@ -125,12 +125,33 @@ do_lost_interrupts:
  * 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 @@ _GLOBAL(_tlbia)
  * 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 @@ _GLOBAL(atomic_set_mask)
  * 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 @@ _GLOBAL(_insb)
        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 @@ _GLOBAL(_outsb)
        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 @@ _GLOBAL(_insw)
        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 @@ _GLOBAL(_outsw)
        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 @@ _GLOBAL(_insl)
        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(_outsl)
 
 _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(_insw_ns)
 
 _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 @@ _GLOBAL(_outsw_ns)
        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 @@ _GLOBAL(_insl_ns)
        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 @@ _GLOBAL(_get_HID0)
        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 @@ _GLOBAL(_set_ICTC)
 /*
        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 @@ _GLOBAL(_set_ICTC)
        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 @@ dontDisableCache:
        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 @@ _GLOBAL(_get_L2CR)
 /* --- 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 @@ sys_call_table:
        .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 @@ sys_call_table:
        .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
index 47b68e68fe2e882c1c24e1c0a469fe1c3deb94a4..c1d99906aab02cc7e6fea50e36a7e6b04e81f5f3 100644 (file)
+/*
+ * 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
 };
index 83ffb7f91d0ab9a59815f2ceb3ba9496d71420d5..7b207ff96bdda19c1a38418d24dd0ffab34f3f05 100644 (file)
@@ -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);
index f93945dd657f4d97e5c4cbfe12c947c24f59477f..be04097691cbca106786a0edc7a75c773c1b5485 100644 (file)
@@ -175,7 +175,10 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
  * 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 @@ __initfunc(void openpic_init(int main_pic))
            
                /* 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 @@ __initfunc(void openpic_init(int main_pic))
                                        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 @@ void openpic_reset(void)
 {
        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 @@ void do_openpic_setup_cpu(void)
        
        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_maptimer(u_int timer, u_int cpumask)
  */
 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 @@ void openpic_enable_irq(u_int irq)
                        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 @@ void openpic_set_sense(u_int irq, int sense)
                                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
index 058dc1f511e711366317d53f4289387690a79e2a..4b0cb9afe7012bebaaaa40f4c2180aa2c23e1221 100644 (file)
 #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 @@ void __init fix_intr(struct device_node *node, struct pci_dev *dev)
        }
 }
 #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;
+}
index 462b92bc70c7d6aad54f85e94c837812e536801d..1216aabe370a906e970316466e7be9b26aea756f 100644 (file)
@@ -32,6 +32,8 @@ struct uninorth_data {
        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 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
        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 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
        |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 @@ static inline void grackle_set_loop_snoop(struct bridge_data *bp, int enable)
        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 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
                               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 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
                        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 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
                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 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
                        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 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
                        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;
index 083e043e8b98dc4748a0798f6fcef8da8924bd82..19e3796d9b74a4af5cc9825097f0a5cbad84ad34 100644 (file)
@@ -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 volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
 
 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 @@ static void __pmac pmac_unmask_irq(unsigned int irq_nr)
         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 @@ struct hw_interrupt_type gatwick_pic = {
        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 @@ pmac_do_IRQ(struct pt_regs *regs,
            int            cpu,
             int            isfake)
 {
+       extern void psurge_smp_message_recv(void);
+
        int irq;
        unsigned long bits = 0;
 
@@ -193,7 +174,7 @@ pmac_do_IRQ(struct pt_regs *regs,
                         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 @@ pmac_do_IRQ(struct pt_regs *regs,
         }
 #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 @@ pmac_pic_init(void))
         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 @@ pmac_pic_init(void))
                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 @@ pmac_pic_init(void))
  * 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,10 +509,11 @@ sleep_save_intrs(int viaint)
 }
 
 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)
                out_le32(&pmac_irq_hw[1]->enable, 0);
index 78def39c36394f6c29a006f7d896156442eea0e0..42d1cfee68a2593bc49f5f59560bf3652ef722fd 100644 (file)
 #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 char mackbd_unexpected_up(unsigned char keycode);
 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 int pmac_newworld;
 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 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
        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 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
                        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 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
 
        *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 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
                                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 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
                                ? "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 ohare_init(void))
        }
 }
 
-__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 @@ __initfunc(void find_boot_device(void))
 
 /* 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 @@ void note_bootable_part(kdev_t dev, int part)
        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 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
        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 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
        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;
index 5edaa85531042f0a78198209dd8c9109fbc7c349..8a976c621a4df44fc47d1096e3736c0d2be898a9 100644 (file)
@@ -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 nvram_mult, is_core_99;
 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 @@ static int nvram_partitions[3];
 #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 @@ chrp_checksum(struct chrp_header* hdr)
        return sum;
 }
 
-static u32
+static u32 __pmac
 core99_calc_adler(u8 *buffer)
 {
        int cnt;
@@ -113,7 +120,7 @@ core99_calc_adler(u8 *buffer)
        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 @@ core99_check(u8* datas)
        return hdr99->generation;
 }
 
-static int
+static int __pmac
 core99_erase_bank(int bank)
 {
        int stat, i;
@@ -163,7 +170,7 @@ core99_erase_bank(int bank)
        return 0;
 }
 
-static int
+static int __pmac
 core99_write_bank(int bank, u8* datas)
 {
        int i, stat = 0;
@@ -191,7 +198,7 @@ core99_write_bank(int bank, u8* datas)
        return 0;       
 }
 
-static void
+static void __pmac
 lookup_partitions(void)
 {
        u8 buffer[17];
@@ -281,7 +288,8 @@ void pmac_nvram_init(void)
        } 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 @@ void pmac_nvram_init(void)
        lookup_partitions();
 }
 
-void
+void __pmac
 pmac_nvram_update(void)
 {
        struct core99_header* hdr99;
@@ -317,7 +325,7 @@ pmac_nvram_update(void)
                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 @@ nvram_read_byte(int addr)
        return 0;
 }
 
-void
+void __pmac
 nvram_write_byte(unsigned char val, int addr)
 {
        struct adb_request req;
@@ -373,13 +381,13 @@ nvram_write_byte(unsigned char val, int addr)
        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 @@ pmac_xpram_read(int xpaddr)
        return nvram_read_byte(xpaddr + offset);
 }
 
-void
+void __pmac
 pmac_xpram_write(int xpaddr, u8 data)
 {
        int offset = nvram_partitions[pmac_nvram_XPRAM];
@@ -401,3 +409,118 @@ pmac_xpram_write(int xpaddr, u8 data)
        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;
+}
+
index d65110d0df51ab64a970bf1424209167c71166ac..f4c5d7f5cf2577a9b63dc8cd3410aa54990a020c 100644 (file)
@@ -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 @@ void pmac_time_init(void)
        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 @@ unsigned long pmac_get_rtc_time(void)
                        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 @@ unsigned long pmac_get_rtc_time(void)
                        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 @@ int pmac_set_rtc_time(unsigned long nowtime)
        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)
@@ -147,15 +144,6 @@ int pmac_set_rtc_time(unsigned long nowtime)
                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;
 }
 
index 813179276e976f239f03063818f85f771d33839b..24d241bba07009aeaceb50a9a2aaf3d252d7c22d 100644 (file)
@@ -587,9 +587,8 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
                        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;
index 54a8f763bfb9d02c1f4bce54ab32eabff15a9392..5a051a79c4ea5ea24bdc35a80a3997943d45b5a3 100644 (file)
@@ -81,8 +81,10 @@ EXPORT_SYMBOL(pci_dram_offset);
 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_lock);
 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(machine_is_compatible);
 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);
 
index 2932aedd5a80e75304e9502af754f78089a4ee8f..71c8bcae54280a34fbd588aa44819329fb159842 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/machdep.h>
 
 #include "pci.h"
+#include "open_pic.h"
 
 #define MAX_DEVNR 22
 
@@ -42,8 +43,6 @@ void Powerplus_Map_Non0(struct pci_dev *);
 /* 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 @@ __initfunc(int raven_init(void))
        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 @@ int motopenpic_to_irq(int n)
        if (n & 0xF0) {
                return (n & 0x0F);
        } else {
-               return(openpic_to_irq(n));
+               return(n+open_pic.irq_offset);
        }
 }
 
@@ -1170,6 +1169,17 @@ struct pci_dev *dev = NULL;
                                        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);
+               }
+       }
 }
 __initfunc(
 void
index 7b8137106f7b74cfc638b3526687e32d3e444fbb..f09627141f397de328aba6e66b5197907f34049b 100644 (file)
 #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_doload;               /* 1 = load ramdisk, 0 = don't load */
 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 @@ prep_init_IRQ(void))
                 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 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
        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
 }
index 0a6b08e66ec37100da31c5d9eea1196f2699c349..3f44de7d31161b353732668b65b29c3eb59796f8 100644 (file)
@@ -233,7 +233,7 @@ void print_bits(unsigned int val, struct bits *bits)
        printk("[");
        for (; bits->bit != 0; ++bits) {
                if (val & bits->bit) {
-                       printk("%s", bits->name);
+                       printk("%s%s", sep, bits->name);
                        sep = ", ";
                }
        }
index 8a240c46e0e3d71c838c573c1174d230a301fb5a..4929adf8ce0644e42545685e4d7aca5d97939125 100644 (file)
@@ -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>
 #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 @@ static struct device_node *allnodes = 0;
 
 #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 drawchar(char c);
 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_loc_Y = 0;
 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 @@ call_prom(const char *service, int nargs, int nret, ...)
        return prom_args.args[nargs];
 }
 
-__init
+/*__init*/
 void
 prom_print(const char *msg)
 {
@@ -399,6 +432,7 @@ prom_init(int r3, int r4, prom_entry pp)
                }
                
 #ifdef CONFIG_BOOTX_TEXT
+               prepare_disp_BAT();
                prom_print(RELOC("booting...\n"));
                flushscreen();
 #endif
@@ -573,7 +607,11 @@ prom_init(int r3, int r4, prom_entry pp)
         * 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 @@ prom_init(int r3, int r4, prom_entry pp)
        }
 
        /* 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 @@ prom_init(int r3, int r4, prom_entry pp)
        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 @@ void showvalue(char *str, unsigned long val)
        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 @@ check_display(unsigned long mem)
        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 @@ check_display(unsigned long mem)
                          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 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start)
                    ((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 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start)
                        /* 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 @@ find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn)
        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 @@ get_property(struct device_node *np, const char *name, int *lenp)
        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 @@ __init
 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 @@ scrollscreen(void)
        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 @@ scrollscreen(void)
                        *(dst_ptr++) = 0;
                dst += (bi->dispDeviceRowBytes >> 2);
        }
+
+#ifdef CONFIG_POWERMAC
+       pmu_resume();
+#endif
 }
 
 __pmac
@@ -2042,6 +2163,16 @@ drawstring(const char *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
 drawhex(unsigned long v)
index 4d3a9a9e36da247f9a9162f2ae826e2b40d46b0b..0c11300c2c246e93fc92d180f8d3a188da41fbcb 100644 (file)
@@ -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 @@ extern void gemini_init(unsigned long r3,
                       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 @@ int is_powerplus = 0;
 
 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 @@ int get_cpuinfo(char *buffer)
                               (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 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 
        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 @@ void ppc_setup_l2cr(char *str, int *ints)
                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 @@ __initfunc(void setup_arch(char **cmdline_p,
        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,8 +610,16 @@ __initfunc(void setup_arch(char **cmdline_p,
        *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)
 {
         int i;
index 1684fd31559ec7db0db26623d88cb6f6edf77611..20c3b1115a6d1740ee2789965583d5acd12aec85 100644 (file)
  *  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 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
 }
 
 
-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 @@ sys_sigaction(int sig, const struct old_sigaction *act,
  * 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 @@ struct sigregs {
        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 @@ badframe:
        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 @@ badframe:
        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 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
              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 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
                 !(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;
-
-       if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
-           || __put_user(oldset->sig[0], &sc->oldmask)
+ /* 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 _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 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
        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;
 
 }
index b73acd6ce156996dc0df66dcc113e84211919a58..e356912b56d805bd37220558e6fc300824386852 100644 (file)
@@ -113,8 +113,8 @@ _GLOBAL(low_sleep_handler)
        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 @@ _GLOBAL(low_sleep_handler)
        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 @@ _GLOBAL(low_sleep_handler)
        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 @@ _GLOBAL(low_sleep_handler)
 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 @@ wake_up:
        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 @@ wake_up:
        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 @@ turn_on_mmu:
        mtsrr1  r3
        sync
        rfi
+       sync
index dea942bc267e09a96ce377db967f42df73ff714f..ac38137c278d4fb5687e6ab9eb5cb84365d1625b 100644 (file)
@@ -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 @@ int smp_num_cpus = 1;
 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 int mot_multi;
 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_local_timer_interrupt(struct pt_regs * regs)
 
 void smp_message_recv(int msg)
 {
-       ipi_count++;
+       atomic_inc(&ipi_recv);
        
        switch( msg )
        {
@@ -136,6 +143,7 @@ void smp_message_recv(int msg)
        }
 }
 
+#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 @@ void smp_message_recv(int msg)
  * 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 @@ void pmac_smp_message_recv(void)
        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 @@ void smp_send_stop(void)
        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 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
        }
 }
 
+#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 @@ void __init smp_boot_cpus(void)
 
        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 @@ void __init smp_boot_cpus(void)
                        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 @@ void __init smp_boot_cpus(void)
                /* 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 @@ void __init smp_boot_cpus(void)
                }
        }
        
-       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 @@ void __init smp_callin(void)
         * 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();
index 0bab2b561505fa40ce0201f6d0e6badf3792ab58..e30a93a81cae0fe3007256ebc83de6c15b3d6ef0 100644 (file)
@@ -283,3 +283,14 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
 
        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
+
index 18eaea64982feff605d9bfee2687676349ac4f44..fbdc74b27c44c91f09f7fe3f55c75d5091785565 100644 (file)
@@ -71,7 +71,7 @@ void timer_interrupt(struct pt_regs * regs)
 {
        int dval, d;
        unsigned long cpu = smp_processor_id();
-       
+
        hardirq_enter(cpu);
 #ifdef __SMP__
        {
@@ -192,10 +192,10 @@ void do_settimeofday(struct timeval *tv)
 
 __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 @@ __initfunc(void time_init(void))
 
         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 */
index 8b119e24000b4969f56b833ba3d66b14fb1531dc..754dbfd06449d0ee964b06516bbb98244078468f 100644 (file)
@@ -156,9 +156,52 @@ RunModeException(struct pt_regs *regs)
        _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 @@ ProgramCheckException(struct pt_regs *regs)
 #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);
+               }
        }
 }
 
index afcf705e14a630314c4d86fa3f229809d9ecaf44..f50f483b5a1f56fa547f54436d7a0e64edef2b32 100644 (file)
@@ -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 @@ search_exception_table(unsigned long addr)
 {
        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;
index 45adbb20aa4191cc7a9ed2dd05407c8f84260f68..613d64a05068b317ce790cc1d4388ab2544f411d 100644 (file)
@@ -1044,6 +1044,9 @@ __initfunc(void free_initmem(void))
  * 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 @@ __initfunc(void MMU_init(void))
                        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 @@ __initfunc(void MMU_init(void))
         ioremap(0x80000000, 0x4000);
         ioremap(0x81000000, 0x4000);
 #endif /* CONFIG_8xx */
+#ifdef CONFIG_BOOTX_TEXT
+       if (_machine == _MACH_Pmac)
+               map_bootx_text();
+#endif
 }
 
 /*
index 18d17bd394a305b849ccef7f9d6528b1529cb084..c853b9b7e4a6fb50eae6b3434d0b3a631ad9d505 100644 (file)
@@ -467,3 +467,15 @@ xmon_fgets(char *str, int nb, void *f)
     *p = 0;
     return str;
 }
+
+void
+xmon_enter(void)
+{
+       pmu_suspend();
+}
+
+void
+xmon_leave(void)
+{
+       pmu_resume();
+}
index f9a4853718690b152a2733aeabb10e01612959e2..d41a9d9d23e402a90064a40eb717861ae8251e66 100644 (file)
@@ -86,6 +86,9 @@ extern int putchar(int ch);
 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 @@ xmon(struct pt_regs *excp)
        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(struct pt_regs *excp)
                xmon_trace = 0;
                insert_bpts();
        }
+       xmon_leave();
        set_msr(msr);           /* restore interrupt enable */
 }
 
index c422ebbf701974c41156ed2ff8d0e50934fe6575..3831979fafa18c0181d0c08529c923200a6ddaa3 100644 (file)
@@ -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 @@ _start: .globl _start
        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 @@ _start: .globl _start
 .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 @@ _start: .globl _start
        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 @@ _start: .globl _start
        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 @@ _start: .globl _start
        lhi     %r6,12
        clc     .Lrdcdata+3(2),.L3390     
        je      .L011                   
-        bras   %r14,.Ldisab
+       bras    %r14,.Ldisab
 .L011: 
        # loop for nbl times
 .Lrdloop:      
index b6c5787f0bd76734a781e29e1276ecb017616807..e1d357979d3c0faf032da8b540f0db407d4ecfb7 100644 (file)
@@ -8,6 +8,7 @@ define_bool CONFIG_ARCH_S390 y
 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
index cb4a8d726246d7626798b8ba57fc7ef0feccd166..77b3c0443ad37dc092047fe857c31c201773d367 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_ARCH_S390=y
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_PROCESS_DEBUG=n
 
 #
 # Processor type and features
@@ -81,7 +82,7 @@ CONFIG_NETLINK=y
 # 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
index fbeee3d8ddd6544a321e9d6d7248b72a245c44e9..93b1a2d0a7562218ad907b403abe5962504eacf5 100644 (file)
@@ -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)
index d03d566110c6ddac8a86da6244543768c58ddf00..f08881a0c917762e083ee9a05e8eaacbf9c13531 100644 (file)
+/*
+ *  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;
-
-debug_info_t *
-debug_register (char *name, int page_order, int nr_areas)
-{
-  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])
+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_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 */ )
+{
+       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;
+               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->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;
+
+       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
+               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
-int
-init_module (void)
-{
-  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;
-}
-
-void
-cleanup_module (void)
-{
-
-  return;
-}
-
-#endif /* 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 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;
+}
+
+/*
+ * 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;
+
+       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 */
index 6affe76f9828f77f1ac89d99d0a85b152ac81454..a5b125e4e7e1d9af91be18f012769f5401cec3ab 100644 (file)
 
 /*
  * 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 @@ SP_CRREGS    =  (SP_TRAP+4)
 /* 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 @@ sysc_dn:
         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 @@ sysc_dn:
 #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 @@ resume:
        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 @@ sysc_leave:
 #
 # 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 @@ sysc_tracesys:
 # 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 @@ sysc_handle_bottom_half:
 #
 # 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 @@ sysc_reschedule:
 # 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 @@ ret_from_fork:
 # 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 @@ sys_execve_glue:
         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 @@ sys_rt_sigreturn_glue:
 #
 # 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 @@ sys_sigsuspend_glue:
        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 @@ sys_rt_sigsuspend_glue:
        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 @@ sys_call_table:
         .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 @@ pgm_check_handler:
         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 @@ pgm_svcper:
         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 @@ io_leave:
 # 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 @@ io_handle_bottom_half:
 #
 # 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 @@ io_reschedule:
 #
 # 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 @@ ext_int_handler:
         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_loop:
 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 @@ restart_go:
 .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
index ff047820cf2e06b47f734313bbfb072392b6f694..10693f696e8d37aa1ad8e3f5bed117bb074af653 100644 (file)
@@ -528,21 +528,21 @@ startup:basr  %r13,0                     # get base
         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 @@ _stext:    basr  %r13,0                    # get base
            .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
 
index d110f9afdcf3f1f941ab66ccc966e99dcdc137ca..283257441e9793d25d8e94e47cfe067bfd905354 100644 (file)
 #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 @@ int get_irq_list(char *buf)
 
                action = ioinfo[i]->irq_desc.action;
                
-               if (!action)
+               if (!action)
                        continue;
 
                p += sprintf(p, "%3d: ",i);
@@ -90,8 +90,8 @@ int get_irq_list(char *buf)
                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 @@ void enable_nop(int irq)
 
 __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 @@ int request_irq( unsigned int   irq,
                  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 ) );
 
 }
 
index f99d721376d1b27931ac14ed54d0a10f5cf14462..2eb2f3da3bb039102d6740a6d67786c38490a5e9 100644 (file)
 
 #include <asm/uaccess.h>
 #include <asm/mathemu.h>
+#include <linux/config.h>
 
-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);
+#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 set_CC_df(__u64 val1,__u64 val2) {
+
+
+static void display_emulation_not_implemented(char *instr)
+{
+       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 int set_CC_df(__u64 val1,__u64 val2) {
         int rc;
         rc = __cmpdf2(val1,val2);
         current->tss.regs->psw.mask &= 0xFFFFCFFF;
@@ -41,9 +82,10 @@ static void set_CC_df(__u64 val1,__u64 val2) {
                         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 @@ static void set_CC_sf(__u32 val1,__u32 val2) {
                         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 @@ static inline void emu_store_rege(int reg) {
 }
 
 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 @@ int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
                 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 @@ static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
 }
     
 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 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
                 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 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
                 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 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
                 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 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
                 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 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
 /*
  * 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 @@ void math_emu_ldr(__u8 *opcode) {
                 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 @@ void math_emu_ler(__u8 *opcode) {
                 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 @@ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
  * 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_stfpc(__u8 *opcode, struct pt_regs *regs) {
  */
 int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
         /* FIXME: how to do that ?!? */
+       display_emulation_not_implemented("srnm");
         return 0;
 }
 
index f71b5fc31e1cf68d733e9493a71ab8125b3bfc9d..7f9a9454644120df63266b16020a265ea0a62e9c 100644 (file)
@@ -76,7 +76,9 @@ int cpu_idle(void *unused)
                 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 @@ asmlinkage int sys_idle(void)
   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 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str
                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 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str
                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 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str
                }
                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 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str
                                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 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
         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 @@ asmlinkage int sys_clone(struct pt_regs regs)
 
         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 @@ asmlinkage int sys_execve(struct pt_regs regs)
                 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();
index 896631756bd3d8cc56d1453547521ca45b0c1387..2b81c03f165007040a2eecd3433f8c78ffdf7b48 100644 (file)
@@ -229,7 +229,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
        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 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
        /* 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) 
        {
index e777170ccc387da1a103643175fd3eba17120ecd..8f2ae4d6f0b06e028caa0f6a4ec31808ba171299 100644 (file)
@@ -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 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         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 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
         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) {
index 58a2568cab7054aac8ebe94f36fa386d8b8b0e5a..2477b5878a16fa39338263a39723ee2417b9d45b 100644 (file)
@@ -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>\r
+#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_request_irq_special);
 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(strnlen);
 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 @@ EXPORT_SYMBOL_NOVERS(_ebc_toupper);
 /*
  * 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(synchronize_bh);
 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
index cf1a9f6a0d557ab71eaa02ec2c9bee21725dd49c..b40201d3f80d806871a68e38fb55a3bd6666441d 100644 (file)
@@ -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)
  */
 
index f1847e31bbf1454fc1d9f2067a33fe2de2014642..0061d46deed517fea5affba9306f87b850523f1c 100644 (file)
@@ -80,6 +80,11 @@ int restore_fp_regs1(s390_fp_regs *fpregs)
 {
        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"
index c63e62852d89308d654101a0d3c3370957c9c122..f256d03f6ea8d0edc0893a4eaa576e09efadc022 100644 (file)
 #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 @@ static int  disable_subchannel( unsigned int irq);
 
 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 @@ void s390_displayhex(char *str,void *ptr,s32 cnt)
 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 @@ int s390_request_irq_special( int                      irq,
        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 @@ int s390_request_irq_special( int                      irq,
                        s390_DevicePathVerification( irq, 0 );
                }
                else
-       {
-               kfree(action);
+               {
+                       kfree(action);
 
-       } /* endif */
+               } /* endif */
 
        } /* endif */
 
@@ -228,7 +228,7 @@ void s390_free_irq(unsigned int irq, void *dev_id)
 
        } /* 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 @@ void s390_free_irq(unsigned int irq, void *dev_id)
                        ioinfo[irq]->ui.flags.unready = 1;
 
                        do
-         {
+                       {
                                ret = disable_subchannel( irq);
 
                                count++;
@@ -305,15 +305,15 @@ void s390_free_irq(unsigned int irq, void *dev_id)
                                                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 @@ void s390_free_irq(unsigned int irq, void *dev_id)
                        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 @@ int enable_irq(unsigned int irq)
  */
 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 @@ static int enable_subchannel( unsigned int irq)
        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 @@ static int enable_subchannel( unsigned int irq)
                        }
                        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 @@ static int enable_subchannel( unsigned int irq)
                                        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 @@ static int enable_subchannel( unsigned int irq)
                                        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 enable_subchannel( unsigned int irq)
  */
 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 @@ static int disable_subchannel( unsigned int irq)
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
        {
                return( -ENODEV);
-   }
+       }
        else if ( ioinfo[irq]->ui.flags.busy )
        {
                /*
@@ -554,17 +554,17 @@ static int disable_subchannel( unsigned int irq)
                {
                        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 @@ static int disable_subchannel( unsigned int irq)
                                        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 @@ unsigned long s390_init_IRQ( unsigned long memstart)
         * 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 @@ unsigned long s390_init_IRQ( unsigned long memstart)
        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 @@ unsigned long s390_init_IRQ( unsigned long memstart)
 
        s390_device_recognition_all();
 
-   init_IRQ_complete = 1;
+       init_IRQ_complete = 1;
 
        __restore_flags(flags);
 
@@ -788,7 +788,7 @@ int s390_start_IO( int            irq,      /* IRQ */
        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 @@ int s390_start_IO( int            irq,      /* IRQ */
 
        } /* 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 @@ int s390_start_IO( int            irq,      /* IRQ */
        case 0:
 
                if ( !ioinfo[irq]->ui.flags.w4sense )
-      {
+               {
                        /*
                         * init the device driver specific devstat irb area
                         *
@@ -895,7 +895,7 @@ int s390_start_IO( int            irq,      /* IRQ */
                } /* 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 @@ int s390_start_IO( int            irq,      /* IRQ */
                 */
                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 @@ int s390_start_IO( int            irq,      /* IRQ */
                                {
                                        tpi_info_t tpi_info;
 
-                       do
-                       {
+                                       do
+                                       {
                                                if ( tpi(&tpi_info) == 1 )
                                                {
                                                        io_sub = tpi_info.irq;
@@ -990,20 +990,20 @@ int s390_start_IO( int            irq,      /* IRQ */
                                                                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 @@ io_wakeup:
                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 @@ io_wakeup:
        
                        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 @@ io_wakeup:
                        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 @@ io_wakeup:
                                         &(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 @@ io_wakeup:
 
 
                        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 @@ io_wakeup:
                ((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 @@ io_wakeup:
                break;
 
        default:            /* device/path not operational */
-
+               
                if ( flag & DOIO_VALID_LPM )
                {
                        ioinfo[irq]->opm &= ~lpm;
@@ -1154,27 +1154,27 @@ io_wakeup:
                        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 @@ io_wakeup:
 
                } 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 @@ io_wakeup:
        {
                ioinfo[irq]->ui.flags.repnone = 0;
 
-       } /* endif */
+   } /* endif */
 
        return( ret);
 }
@@ -1324,27 +1324,27 @@ int resume_IO( int irq)
                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 @@ int resume_IO( int irq)
  *       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 halt_IO( int          irq,
                        {
                                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 @@ int halt_IO( int          irq,
                                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 @@ hio_wakeup:
                        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 @@ hio_wakeup:
                         */
                        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 @@ hio_wakeup:
                {
                        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 @@ int clear_IO( int           irq,
               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 @@ int clear_IO( int           irq,
        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 @@ int clear_IO( int           irq,
        {
                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 @@ int clear_IO( int           irq,
                        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 @@ int clear_IO( int           irq,
                                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 @@ int clear_IO( int           irq,
                         *  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 @@ int clear_IO( int           irq,
                                 *  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 @@ int clear_IO( int           irq,
 
                                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 @@ cio_wakeup:
 
                                *(__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 @@ cio_wakeup:
                                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 @@ cio_wakeup:
                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 @@ asmlinkage void do_IRQ( struct pt_regs regs,
                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 @@ asmlinkage void do_IRQ( struct pt_regs regs,
 
 #ifdef CONFIG_FAST_IRQ
 
-                          /*
+               /*
                 * more interrupts pending ?
-                           */
+                */
                ccode = tpi( &tpi_info );
 
                if ( ! ccode )
@@ -1993,29 +1993,29 @@ asmlinkage void do_IRQ( struct pt_regs regs,
 
                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 @@ asmlinkage void do_IRQ( struct pt_regs regs,
  *
  * 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 @@ int s390_process_IRQ( unsigned int irq )
        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 @@ int s390_process_IRQ( unsigned int irq )
                                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 @@ int s390_process_IRQ( unsigned int irq )
         *         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 @@ int s390_process_IRQ( unsigned int irq )
                             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 @@ int s390_process_IRQ( unsigned int irq )
                                        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 @@ int disable_cpu_sync_isc( int irq)
 //
 // 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 @@ void VM_virtual_device_info( unsigned int  devno,
 
                        error = 1;
 
-               break;
+                       break;
 
                } /* endswitch */
 
@@ -3322,19 +3320,19 @@ int read_dev_chars( int irq, void **buffer, int length )
    }
 
        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 @@ int read_dev_chars( int irq, void **buffer, int length )
        if ( !ret )
        {
                if ( ! *buffer )
-       {
+               {
                        rdc_buf  = kmalloc( length, GFP_KERNEL);
-   }
-       else
-       {
+               }
+               else
+               {
                        rdc_buf = *buffer;
 
                } /* endif */
@@ -3375,7 +3373,7 @@ int read_dev_chars( int irq, void **buffer, int length )
                        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 @@ int read_dev_chars( int irq, void **buffer, int length )
                } /* 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 @@ int read_dev_chars( int irq, void **buffer, int length )
        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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
        if ( (irq > highest_subchannel) || (irq < 0 ) )
        {
                return( -ENODEV );
-                               }
+       }
        else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
        {
                return( -ENODEV);
@@ -3456,12 +3454,12 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
        {
                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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                        {
                                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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                                emulated = 1;
 
                        } /* endif */
-                               }
+               }
                else
-                               {
+               {
                        pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
 
                } /* endif */
@@ -3519,9 +3518,9 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                        {
                                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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                        {
                                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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                                                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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                                           | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
                       {
                       retry = 0;  // we got it ...
-       }
-       else
-       {
+                }
+                     else
+                  {
                           retry--;    // try again ...
 
-       } /* endif */
+                      } /* endif */
 
                    break;
 
@@ -3612,9 +3611,9 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
                                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 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
 
                        *buffer = NULL;
                        *length = 0;
-
+       
                } /* endif */
 
                if ( emulated )
@@ -3645,7 +3644,6 @@ int get_dev_info( int irq, dev_info_t * pdi)
        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 @@ static int __inline__ get_next_available_irq( ioinfo_t *pi)
                        if ( pi == NULL )
                        {
                                ret_val = -ENODEV;
-                       break;
+                               break;
                        }
 
                } /* endif */
@@ -3696,7 +3694,7 @@ int get_irq_first( void )
                else
                {
                        ret_irq = -ENODEV;
-
+       
                } /* endif */
        }
        else
@@ -3820,8 +3818,8 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi)
                             && 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 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi)
                                else
                                {
                                        pdi->status = DEVSTAT_NOT_OPER;
-
+       
                                        memset( &(pdi->sid_data),
                        '\0',
                        sizeof( senseid_t));
@@ -3858,7 +3856,7 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi)
                                        pdi->status |= DEVSTAT_DEVICE_OWNED;
 
                                rc = 0; /* found */
-                       break;
+                               break;
 
                        } /* endif */
 
@@ -3889,7 +3887,7 @@ int get_irq_by_devno( unsigned int devno )
                        } /* endif */
 
                } /* endfor */
-
+       
        } /* endif */
 
        return( rc);
@@ -3903,7 +3901,7 @@ unsigned int get_devno_by_irq( int irq )
             || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
        {
                return -1;
-
+       
        } /* endif */
 
        /*
@@ -3955,7 +3953,7 @@ void s390_device_recognition_irq( int irq )
                         *  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 @@ void s390_device_recognition_irq( int irq )
                        }
                        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 @@ void s390_device_recognition_irq( int irq )
                        free_irq( irq, &devstat );
 
                } /* endif */
-
+               
        } /* endif */
 
 }
@@ -4063,13 +4061,14 @@ void s390_process_subchannels( void)
        {
                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 @@ int s390_validate_subchannel( int irq, int enable )
                {
                        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
                        {       
-
                                if ( !init_IRQ_complete )
                                {
                                        ioinfo[irq] =
@@ -4156,7 +4154,7 @@ int s390_validate_subchannel( int irq, int enable )
                                   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 @@ int s390_validate_subchannel( int irq, int enable )
                                                        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 @@ int s390_validate_subchannel( int irq, int enable )
                                ioinfo[irq]->schib.pmcw.pam,
                                ioinfo[irq]->schib.pmcw.pom);
 
-/*
+                       /*
                         * initialize ioinfo structure
                         */
                        ioinfo[irq]->irq             = irq;
@@ -4232,9 +4230,9 @@ int s390_validate_subchannel( int irq, int enable )
 
                        /*
                         * We should have at least one CHPID ...
- */
                       */
                        if ( ioinfo[irq]->opm )
-{
+                       {
                                /*
                                 * We now have to initially ...
                                 *  ... set "interruption sublass"
@@ -4260,15 +4258,15 @@ int s390_validate_subchannel( int irq, int enable )
                                     && ( 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 @@ int s390_validate_subchannel( int irq, int enable )
                                                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 @@ int s390_validate_subchannel( int irq, int enable )
                                                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 @@ int s390_validate_subchannel( int irq, int enable )
 #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 @@ int s390_validate_subchannel( int irq, int enable )
                                } 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 @@ int s390_validate_subchannel( int irq, int enable )
                        } /* endif */
                }
                else
-    {
+               {
                        ret = -ENODEV;
 
-    } /* endif */
+               } /* endif */
        }
        else
        {
-               
                ret = -ENXIO;
 
-  } /* endif */
+       } /* endif */
 
-  return( ret );
+       return( ret );
 }
 
 /*
@@ -4417,70 +4414,70 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
        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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                domask &= lpm;
 
                        if ( domask )
-               {
+                       {
                                psid->cu_type    = 0xFFFF;  /* initialize fields ... */
                                psid->cu_model   = 0;
                                psid->dev_type   = 0;
@@ -4504,14 +4501,14 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
 
                                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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                        //
 
                                        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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                } /* 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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                                        irq);
 #endif
                                                                io_retry = 1;
-               }
+                                                       }
 #ifdef CONFIG_DEBUG_IO
-               else
-               {
+                                                       else
+                                                       {
                                                                printk( "SenseID : UC on "
                                                                        "dev %04X, "
                                                                        "retry %d, "
@@ -4590,12 +4587,12 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                                        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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
 
                                                        io_retry          = 0;
                                                        ioinfo[irq]->opm &= ~domask;
-
-}
+       
+                                               }
 #ifdef CONFIG_DEBUG_IO
                                                else if (     (pdevstat->flag !=
                                                                    (   DEVSTAT_START_FUNCTION
@@ -4630,11 +4627,11 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
 
                                                } /* endif */
 #endif
-       }
+                                       }
                                        else   // we got it ...
-       {
+                                       {
                                                if ( !sbuffer ) // switch buffers
-       {
+                                               {
                                                        /*
                                                         * we report back the
                                                         *  first hit only
@@ -4642,14 +4639,14 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                        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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
 
                                                        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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                } /* 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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                /*
                 * 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 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                        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 @@ static int __inline__ s390_SetMultiPath( int irq )
        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 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
        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 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
                                   & 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 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
 
                        ioinfo[irq]->ui.flags.pgid  = 1;
 
-               } /* endif */
+               } /* endif */                   
 
                memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t));
 
@@ -4865,7 +4862,7 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
                        domask = dev_path & pathmask;
 
                        if ( domask )
-                               {
+                       {
                                ret = s390_SetPGID( irq, domask, &pgid );
 
                                /*
@@ -4879,30 +4876,30 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
                                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 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
                                                        " 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 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
 #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 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
 
        }
        else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-                       {
+       {
                return( -ENODEV);
 
        } /* endif */
@@ -5001,7 +4998,7 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
        } /* endif */
 
        if ( irq_ret == 0 )
-                                  {
+       {
                s390irq_spin_lock( irq);
 
                spid_ccw[0].cmd_code = 0x5B;    /* suspend multipath reconnect */
@@ -5010,16 +5007,16 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
                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 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
 
                                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 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
                                                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_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
 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 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                /*
                 * 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 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
        } /* 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 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                                                  | DOIO_DONT_CALL_INTHDLR );
 
                        if ( irq_ret == 0 )
-                               {
+                       {
                                if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
                                {
                                        /*
@@ -5230,7 +5227,7 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                                         */
                                        if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
                                        {
-                                               retry = 0;
+                                               retry   = 0;
                                                irq_ret = -EOPNOTSUPP;
                                        }
                                        else
@@ -5270,12 +5267,12 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
 
                                        retry = 0;
 
-                       }
+                               }
                                else
-                       {
+                               {
                                        retry = 0; // success ...
 
-                       } /* endif */
+                               } /* endif */
                        }
                        else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
                        {
@@ -5296,7 +5293,7 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                                        " start_io() reports rc : %d, retrying ...\n",
                                        ioinfo[irq]->schib.pmcw.dev,
                                        irq_ret);
-                       retry--;
+                               retry--;
                        }
                        else    // -ENODEV ...
                        {
@@ -5320,16 +5317,16 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
    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 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #endif
 
        while ( pcrwe != NULL )
-               {
+       {
                switch ( pcrwe->crw.rsc ) {     
                case CRW_RSC_SCH :
 
@@ -5364,7 +5361,7 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                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 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #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 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                        } /* 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 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                        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 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                                        if ( pdevreg->oper_func != NULL )
                                                                pdevreg->oper_func( irq, pdevreg );
 
-                       } /* endif */
+                                               } /* endif */
                                        }
                                        /*
                                         * ... it is and was operational, but
@@ -5453,11 +5450,11 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                                ioinfo[irq]->nopfunc( irq,
                                                                      DEVSTAT_REVALIDATE );                             
 
-               } /* endif */
+                                       } /* endif */
 
                                } /* endif */
 
-       } /* endif */
+                       } /* endif */
 
                        break;
 
@@ -5516,13 +5513,13 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 
 /* 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 );
 }
index 898f0307e4625eefe04bca76dde7cdf350510248..a055fc59f8fb04d1a07793c6e8cce77e099de45c 100644 (file)
@@ -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)
  */
 
 #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 @@ void s390_init_machine_check( void )
        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 @@ void s390_init_machine_check( void )
 
                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 @@ void s390_init_machine_check( void )
        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 @@ void s390_init_machine_check( void )
  * 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 @@ void __init s390_do_machine_check( void )
 
                if ( crw_count )
                {
-                       up( &s_sem[1] );
+                       up( &s_sem );
 
                } /* endif */
 
@@ -183,7 +173,7 @@ void __init s390_do_machine_check( void )
  * 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 @@ static int __init s390_machine_check_handler( void *parm)
 
        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 @@ static int __init s390_machine_check_handler( void *parm)
                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 @@ static int __init s390_machine_check_handler( void *parm)
                }
                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);
 }
index c7fdaa6825541b88c3814146bc3e01dca2d47b4c..5b362dc8322333bc27f197357b3cfde68c562656 100644 (file)
@@ -137,7 +137,7 @@ __initfunc(void vmpoff_setup(char *str, char *ints))
 #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 @@ void machine_halt(void)
         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 @@ void tod_wait(unsigned long delay)
 __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;
 
index cdd09d293d18e7d240be6f0f9be74bf456197b15..121c0155f6a7ec6e75d20bf9f9ea00c4003b0b44 100644 (file)
@@ -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 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma
                schedule();
                if (do_signal(regs, &saveset))
                        return -EINTR;
-         }
+       }
 }
 
 asmlinkage int
@@ -100,17 +100,17 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
        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 @@ sys_sigaction(int sig, const struct old_sigaction *act,
                __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 @@ sys_sigaction(int sig, const struct old_sigaction *act,
                        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 save_sigregs(struct pt_regs *regs,sigregs *sregs)
        
 }
 
-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_sigregs(struct pt_regs *regs,sigregs *sregs)
 
 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 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
 
        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 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 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 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
                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 @@ give_sigsegv:
 
 /*
  * 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 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
  * 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 @@ int do_signal(struct pt_regs *regs,sigset_t *oldset)
                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;
 }
index 80b4acc2764654a846046f50f27fac84decf2a87..2e36f6800e7c3cf13bef5fe3c4c4b8c986d0ddf1 100644 (file)
@@ -108,7 +108,7 @@ void do_machine_halt(void)
         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 @@ void do_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);
-        }
+}
 
 void machine_power_off(void)
 {
@@ -248,6 +248,14 @@ void do_ext_call_interrupt(struct pt_regs *regs, __u16 source_cpu_addr)
                        __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 @@ void smp_ctl_clear_bit(int cr, int bit) {
         __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 @@ void __init smp_boot_cpus(void)
         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");
index 3afac79365f4c19c182b3a72f990eb50257eaf09..9233188885991b994c5ec0a63cbc587a55012165 100644 (file)
@@ -43,134 +43,14 @@ extern void handle_per_exception(struct pt_regs *regs);
 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 @@ void die(const char * str, struct pt_regs * regs, long err)
         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 @@ int do_debugger_trap(struct pt_regs *regs,int signal)
        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 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
                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 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
                        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 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
                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 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
                 }
         } 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 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code)
                        (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 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code)
                        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 @@ void handle_per_exception(struct pt_regs *regs)
                /* 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;
        }
index c098792b435a5413b3d1d145e6f317753fc9b2ee..a9a9e362416a5508b5384751035cef1c9cd00b9e 100644 (file)
@@ -11,7 +11,7 @@ else
 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
 
index 136218a6783f9cf31da97728ae947ed0ea29ee1f..d13b1efe49f9bb4c2c7df65d263c1ab662508337 100644 (file)
@@ -27,7 +27,7 @@ void __delay(unsigned long loops)
          * 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 --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
new file mode 100644 (file)
index 0000000..8044d15
--- /dev/null
@@ -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
+
index 7f777fbebb5886b578d0bf1b09f5f316414a6497..5ee70d1fa1a4d50d3b73ef9092da8fb1c30dd894 100644 (file)
@@ -48,6 +48,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
         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 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
         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 @@ bad_area:
         /* 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 @@ bad_area:
 /*
  * 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 @@ bad_area:
  */
 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 @@ do_sigbus:
         * 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 */
index bc90b951414125b2cd19f59f7fc7c1638f6d944c..7a3cc5cb6d4e252b94eff582a44e03ee4eb1d161 100644 (file)
@@ -251,6 +251,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
         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 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
         /* 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();
 
index 9cbf87ab79e8a9de481e51c4e5aba0028658c278..906151fbc7fe42934618914c76e8aea97d25f17f 100644 (file)
@@ -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"\r
+.UC 4\r
+.SH NAME\r
+dasdfmt \- formatting of DSAD (ECKD) disk drives.\r
+.SH SYNOPSIS\r
 \fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR\r
-.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\r
+\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it\r
+for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of\r
+\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.\r
+\r
+.SH OPTIONS\r
+.TP\r
+\fB-t\fR\r
+Disables any modification of the disk drive. \fBdasdfmt\fR just prints\r
+out, what it \fBwould\fR do.\r
+\r
+.TP\r
+\fB-v\fR\r
+Increases verbosity.\r
+\r
+.TP\r
+\fB-y\fR \r
+Start formatting without further user-confirmation.\r
+\r
+.TP\r
 \fB-L\fR \r
 Omit the writing of a disk label after formatting.\r
 \r
 .TP\r
-\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 \r
+Print version number and exit.\r
+\r
+.TP\r
+\fB-b\fR \fIblockSize\fR\r
+Specify blocksize to be used. \fIblocksize\fR must be a positive integer\r
+and always be a power of two. Due due some limitations in the driver,\r
+it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.\r
+\r
+.TP\r
 \fB-l\fR \fIdiskLabel\fR\r
 Specify the label to be written to disk after formatting. If no label is\r
 specified, a sensible default is used. \fIdiskLabel\fR is interpreted as\r
 ASCII string and is automatically converted to EBCDIC.\r
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
+\r
+.TP\r
+\fIdiskSpec\fR\r
+This parameter specified the device to be formatted. It also can be\r
+given in two variants:\r
+.sp\r
        \fB-f\fR \fB/dev/dasd\fR\fIX\fR\r
-.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\r
+or\r
+.br\r
+       \fB-n\fR \fIdevnum\fR\r
+.sp\r
+The first form uses the commonly used\r
+.SM UNIX\r
+device notation where \fIX\fR is a single lowercase letter.\r
 The second form uses simply the device number.\r
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
+\r
+.SH BUGS\r
+None so far ;-)\r
+\r
+.SH AUTHOR\r
+.nf\r
+This man-page was written by Fritz Elfert <felfert@to.com>\r
+.fi\r
index 9f86a8f0477d5b92febf00f7aa3ad981f7074b8d..3ad43ba2b2f151fafb96ca5a2d3d50f6de961be2 100644 (file)
@@ -458,12 +458,11 @@ check_mounted(int major, int minor)
 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 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
                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 @@ int main(int argc,char *argv[]) {
        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 @@ int main(int argc,char *argv[]) {
 
        /******* 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 --git a/arch/s390/tools/hwc/Makefile b/arch/s390/tools/hwc/Makefile
new file mode 100644 (file)
index 0000000..1d5e4ec
--- /dev/null
@@ -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 --git a/arch/s390/tools/hwc/hwc_cntl_key.c b/arch/s390/tools/hwc/hwc_cntl_key.c
new file mode 100644 (file)
index 0000000..e5403aa
--- /dev/null
@@ -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 --git a/arch/s390/tools/hwc/hwc_measure.c b/arch/s390/tools/hwc/hwc_measure.c
new file mode 100644 (file)
index 0000000..2570ab4
--- /dev/null
@@ -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 --git a/arch/s390/tools/hwc_cntl_key/Makefile b/arch/s390/tools/hwc_cntl_key/Makefile
deleted file mode 100644 (file)
index 111f298..0000000
+++ /dev/null
@@ -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 --git a/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c b/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c
deleted file mode 100644 (file)
index e5403aa..0000000
+++ /dev/null
@@ -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;
-}
index 6cc01a4cafae9c4dbb189f18510ef6cff7f8e906..99a098b926e2ca6fb95928480350faffd2a4a21c 100644 (file)
@@ -144,7 +144,7 @@ read_cfg(struct silo_options *o)
        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 @@ gen_tmpparm( char *pfile )
                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 @@ gen_tmpparm( char *pfile )
                }
        }
        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 @@ verify_file (char *name, int dev)
   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 @@ verify_options (struct silo_options *o)
   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 @@ write_bootsect (struct silo_options *o, struct blocklist *blklst)
       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 @@ write_bootsect (struct silo_options *o, struct blocklist *blklst)
   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);
index 136b0a9812d1f88a5823704e3446c95388d0e48d..f33939b2941043caa9eb7436677b3680658ada93 100644 (file)
@@ -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 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        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:
index 61aa7a7140ba006489157c045e2127666219584e..57b2b05101fee9cc286277a9404d31cd8e4dbe5b 100644 (file)
@@ -43,7 +43,7 @@ SUB_DIRS += video
 MOD_SUB_DIRS += video
 endif
 
-ifdef CONFIG_PPC
+ifdef CONFIG_POWERMAC
 SUB_DIRS += macintosh
 MOD_SUB_DIRS += macintosh
 endif
index 4faeb42e4abd519decda423bd8c951d778ee52ea..86f388d6c27a2a6293f7036584cd292dfa064e11 100644 (file)
@@ -53,7 +53,7 @@ else
           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
index 7f4fd9212f721c1676e44db9c368c02ac91114ee..25e9d786d5e5899e9e094d44b4f01b94a5b3347e 100644 (file)
 #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 scsi_dev_init(void);
 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 @@ static char *raid_name (struct gendisk *hd, int minor, int major_base,
         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 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
        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 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
                                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 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
        }
 #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 @@ static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_
 #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 (struct gendisk *hd, kdev_t dev, int first_sector)
        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 @@ ibm_partition (struct gendisk *hd, kdev_t dev, int first_sector)
                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 @@ static inline void setup_dev(struct gendisk *dev)
                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;
        }
index e66320309d549fcd95bb0dfc4155d8721a561dac..ac2230abe9f7e6ea588ab08314c0e674d9fe0814 100644 (file)
@@ -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 @@ static pmac_ide_timing udma_timings[] =
 
 /* 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 @@ pmac_ide_probe(void))
                         */
                         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 @@ udma_bits_to_command(unsigned char bits)
 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 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
        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 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 #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 @@ static void idepmac_sleep_disk(int i, unsigned long base)
                        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 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
                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];
+
+                       /* 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;
 
-#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                         
+                       /* 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 */
index d39af4f01666acbd732c9e69687755ca3edcd838..f1d54b24810aa6ff3a72ebb7e421ff0c3b40bb60 100644 (file)
@@ -614,8 +614,10 @@ __initfunc(static void rd_load_disk(int n))
 #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");
index 355ca2bf514d4287b420aaa34585e9e75b1dc14d..26793bfd284124a95bb434d4485a3a2def948b4d 100644 (file)
@@ -189,7 +189,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
     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
index be201e9d99d0bb75e0207acd1e2090ef96355a9b..c186b063a6b0ff2977eeb2d859717a4f3ab1ab7f 100644 (file)
@@ -2390,7 +2390,7 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
        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 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        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 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
        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 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                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 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 
                        /* 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 @@ static int zr36057_init(int i)
 
        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() */
index 01bb86f3eb3a9d1e9a161d34a00c86242b8ce055..c249016a4024892f77907ad7358584387bc3b12d 100644 (file)
@@ -575,10 +575,12 @@ void redraw_screen(int new_console, int is_switch)
        }
 
        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);
index 1c17a987fea7a77ab079d7a7359999f9a329d298..e4624e9cbdccc7666496dc4089468bf8044bd0be 100644 (file)
@@ -315,7 +315,7 @@ void handle_scancode(unsigned char scancode, int down)
 #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 @@ void compute_shiftstate(void)
            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))
index 2a83f6d68c0ac652f4e7fd78df06365afec1afa0..f0d7b690b939a97c7701bf2a1ce26223fc9d51e3 100644 (file)
@@ -52,12 +52,6 @@ extern void prom_con_init(void);
 #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 @@ __initfunc(int chr_dev_init(void))
        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
@@ -665,9 +656,6 @@ __initfunc(int chr_dev_init(void))
 #ifdef CONFIG_VIDEO_BT848
        i2c_init();
 #endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
-       adbdev_init();
-#endif
 #ifdef CONFIG_VIDEO_DEV
        videodev_init();
 #endif
index c776f6fd5aee352d99b9f0d3c73ba53892561d2f..1f4210d574ec5420901842835e0831c185335d09 100644 (file)
@@ -248,7 +248,7 @@ int __init misc_init(void)
 #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
index 19f2177bc0493c5f6ffea950cd77b0a623af28fc..fe4a15be0c76d2f6409cb5b8d1f0138d9e7d5cbc 100644 (file)
@@ -129,6 +129,9 @@ static int tty_fasync(int fd, struct file * filp, int on);
 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 @@ long __init console_init(long kmem_start, long kmem_end)
 #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 */
index a2d446440fdecb69b3aa60d4e4d368179c5bc9b3..07b6b4e95eab6caab052d05d1cba97303b60a6d8 100644 (file)
 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 @@ else
 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 @@ else
 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 @@ else
 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
index 7c2b45fd439c50e7300f71da51f6177c8d7056f6..14968880aeca4b3caecfe3a475a855bd255fb34b 100644 (file)
 #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 @@ adb_get_infos(int address, int *original_address, int *handler_id)
 
 #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 @@ static struct file_operations adb_fops = {
        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 --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
new file mode 100644 (file)
index 0000000..ffa26ef
--- /dev/null
@@ -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 --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
new file mode 100644 (file)
index 0000000..73529fc
--- /dev/null
@@ -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 */
+}
index ab90dcef6492707e7a138f5241e65ec874795df3..db365794f87c1164a954f35158cf9fc4016f4023 100644 (file)
@@ -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)
 #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 u_short macctrl_alt_map[NR_KEYS] __initdata = {
 
 
 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 @@ input_keycode(int keycode, int repeat)
 #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 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
 }
 #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 @@ static void leds_done(struct adb_request *req)
 
 }
 
-__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 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
        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 @@ mackeyb_probe(void)
 
                        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 @@ mackeyb_probe(void)
         }
 }
 
-static void 
+static void
 init_trackpad(int id)
 {
        struct adb_request req;
@@ -895,15 +887,15 @@ init_trackpad(int id)
 
             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 @@ init_trackpad(int id)
         }
 }
 
-static void 
+static void
 init_trackball(int id)
 {
        struct adb_request req;
@@ -1000,7 +992,7 @@ init_microspeed(int 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)
@@ -1015,7 +1007,7 @@ init_microspeed(int id)
             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 @@ init_ms_a3(int id)
        ADB_WRITEREG(id, 0x2),
            0x00,
            0x07);
+
        adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
  }
 
index d3d5686c9758c06dbb0d307afcee3ddd76357fcc..9b3bafeba5e6b4d2ca1c455053cf815cb13dd420 100644 (file)
@@ -953,6 +953,67 @@ static void dma_init(struct mac_serial * info)
        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 @@ static int setup_scc(struct mac_serial * info)
 
        save_flags(flags); cli(); /* Disable interrupts */
 
+       /* Nice buggy HW ... */
+       fix_zero_bug_scc(info);
+
        /*
         * Reset the chip.
         */
@@ -1081,7 +1145,7 @@ static void shutdown(struct mac_serial * info)
 
        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 @@ static void irda_setup(struct mac_serial *info)
 
        /* 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 @@ static void rs_throttle(struct tty_struct * tty)
        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 @@ static void rs_unthrottle(struct tty_struct * tty)
                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 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
        /* 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 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
        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 @@ int macserial_init(void)
                        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 @@ static struct console sercons = {
 /*
  *     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;
index 26e28ead0aa58b1e2c0ae46b9d9d578a6b9fe1e9..80c4351bd5e5c796c7e040568061e7332b578cb3 100644 (file)
@@ -110,6 +110,7 @@ struct mac_serial {
        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 */
index 2f0a420c7d3341323ba62215b384a98092b01c1a..7087a3c4272f088a1e98c6041b910017a48868a1 100644 (file)
@@ -474,8 +474,11 @@ media_bay_step(int i)
                } 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 @@ poll_media_bay(int which)
 
 #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 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
                           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 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
                        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);
index 695946c3a5a930acffe189f2c64c0430126d0946..9c1580b3c6317318333fcacba95aee82d512b14d 100644 (file)
@@ -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 @@ static ssize_t write_nvram(struct file *file, const char *buf,
        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 @@ struct file_operations nvram_fops = {
        write_nvram,
        NULL,           /* nvram_readdir */
        NULL,           /* nvram_select */
-       NULL,           /* nvram_ioctl */
+       nvram_ioctl,
        NULL,           /* nvram_mmap */
        nvram_open,
        NULL,           /* flush */
index 577820ea10701be533bc9f1e83136cae93fe413f..3164b9e8dc2303d9b50ea36f0eff875b69265d84 100644 (file)
@@ -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>
 #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 adb_request bright_req_1, bright_req_2, bright_req_3;
 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 @@ static void pmu_handle_data(unsigned char *data, int len,
                            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 @@ static struct adb_controller       pmu_controller = {
 };
 
 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_read_config_word(unsigned char bus,
 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 @@ static char *pbook_type[] = {
        "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 @@ find_via_pmu()
                        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 @@ find_via_pmu()
 
                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 @@ via_pmu_init(void)
        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 @@ init_pmu()
        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 @@ init_pmu()
                while (!req.complete)
                        pmu_poll();
        }
-
+               
        return 1;
 }
 
@@ -553,8 +572,8 @@ pmu_queue_request(struct adb_request *req)
        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_queue_request(struct adb_request *req)
                        pmu_start();
        }
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&pmu_lock, flags);
        return 0;
 }
 
@@ -639,35 +658,90 @@ out:
 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 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
        /* 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 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
                        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 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
                }
        }
        --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 @@ pmu_sr_intr(struct pt_regs *regs)
        /* 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 @@ pmu_sr_intr(struct pt_regs *regs)
                        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 @@ pmu_sr_intr(struct pt_regs *regs)
                                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 @@ pmu_sr_intr(struct pt_regs *regs)
                        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 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
                }
        } 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 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
        }
 }
 
-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_enable_backlight(int on)
                    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 @@ broadcast_sleep(int when, int fallback)
                               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 @@ pbook_pci_restore(void)
        }
 }
 
-#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 @@ void pmu_blink(int n)
  * 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 @@ void pmu_blink(int n)
 
 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 @@ int __openfirmware powerbook_sleep_G3(void)
        }
 
        /* 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 @@ int __openfirmware powerbook_sleep_G3(void)
        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 @@ int __openfirmware powerbook_sleep_G3(void)
        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 @@ int __openfirmware powerbook_sleep_G3(void)
        return 0;
 }
 
+#endif
+
 #define PB3400_MEM_CTRL                ((unsigned int *)0xf8000070)
 
 int __openfirmware powerbook_sleep_3400(void)
@@ -1328,7 +1608,7 @@ int __openfirmware powerbook_sleep_3400(void)
        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 @@ int __openfirmware powerbook_sleep_3400(void)
        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 @@ int __openfirmware powerbook_sleep_3400(void)
        }
 
        /* 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 @@ int __openfirmware powerbook_sleep_3400(void)
        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 @@ int __openfirmware powerbook_sleep_3400(void)
                mb();
 
        /* reenable interrupts */
-       sleep_restore_intrs();
+       pmac_sleep_restore_intrs();
 
        /* Notify drivers */
        broadcast_wake();
@@ -1576,20 +1860,24 @@ static int pmu_ioctl(struct inode * inode, struct file *filp,
                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 @@ void pmu_device_init(void)
 }
 #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 @@ pmu_polled_request(struct adb_request *req)
        restore_flags(flags);
        return 0;
 }
-#endif /* 0 */
+#endif /* DEBUG_SLEEP */
index 9eb96e8ac34412c1b9e415f53f80a843237a422d..c8cb6dbf2761daf4a9b9870e359cb128113ec1d6 100644 (file)
@@ -248,12 +248,16 @@ bmac_reset_chip(struct device *dev)
        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)
index 7ec8407eaecd7b33b0b70ae3a0e5c6574247be44..47a3c1c78ddbd2caca178d64202be12858c198bd 100644 (file)
@@ -4165,7 +4165,7 @@ get_hw_addr(struct device *dev)
     /* 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 @@ get_hw_addr(struct device *dev)
            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);
index 76f92dc9b7972195d61c887444caa602b963a242..3e625911a4da6c6c9c62ec7da07c8e084ebf7789 100644 (file)
@@ -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>
 #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_poll_stop(struct gmac *gm);
 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 @@ int gmac_probe(struct device *dev);
 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 @@ mii_poll_stop(struct gmac *gm)
        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 @@ mii_interrupt(struct gmac *gm)
        /* 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 @@ mii_interrupt(struct gmac *gm)
                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 @@ mii_interrupt(struct gmac *gm)
 #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");
@@ -193,17 +253,74 @@ mii_interrupt(struct gmac *gm)
        }
 }
 
+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 @@ mii_lookup_and_reset(struct gmac *gm)
                        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 @@ mii_lookup_and_reset(struct gmac *gm)
 #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 @@ static void
 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 @@ gmac_set_power(struct gmac *gm, int power_up)
        } 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 @@ gmac_set_duplex_mode(struct gmac *gm, int full_duplex)
        }
 }
 
+/* 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 @@ gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
                (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 @@ gmac_close(struct device *dev)
        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 @@ gmac_tx_timeout(struct device *dev)
        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 @@ gmac_tx_timeout(struct device *dev)
        /* Restart chip */
        gmac_start_dma(gm);
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&gm->lock, flags);
        
        dev->tbusy = 0;
 }
@@ -770,6 +946,7 @@ gmac_xmit_start(struct sk_buff *skb, struct device *dev)
        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 @@ gmac_xmit_start(struct sk_buff *skb, struct device *dev)
                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 @@ gmac_xmit_start(struct sk_buff *skb, struct device *dev)
 
        dev->tbusy = (gm->tx_buff[gm->next_tx] != 0);
 
+       spin_unlock_irqrestore(&gm->lock, flags);
+
        return 0;
 }
 
@@ -820,9 +1002,8 @@ gmac_tx_cleanup(struct device *dev, int force_cleanup)
        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 @@ gmac_tx_cleanup(struct device *dev, int force_cleanup)
                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 @@ gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        }
        
        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 @@ gmac_probe(struct device *dev)
        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 @@ gmac_probe(struct device *dev)
 
        gmacs = dev;
 
+#ifdef CONFIG_PMAC_PBOOK
+       pmu_register_sleep_notifier(&gmac_sleep_notifier);
+#endif
        return 0;
 }
 
index 6473ec54eb1507d71d8bb609a2b79666543dd3a5..128e3f2076c709c6af7d577f1e161d8cb86cd92d 100644 (file)
  */
 
 /* 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) */
 #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
 #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_dma_desc {
         
 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 @@ struct gmac {
        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;
 };
 
index a248b27227ed67939bb884996055c1c370bc28a4..2ac145a1198e88b379c80a6589157033a259b6ab 100644 (file)
@@ -50,6 +50,7 @@ static const char* version = "HDLC support routines revision: 1.0";
 #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 @@ static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
                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 @@ static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
                } /* 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++;
index b8a092c54175323d7d8403e74db4f051f81ff6f9..53f5b894d237b86b63191fbec21436e2d7c5562c 100644 (file)
@@ -52,7 +52,7 @@ if [ "$CONFIG_NET" = "y" ]; then
   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
index ad92e36a1cccb56204ba191d10af5e4bdba5a54c..89174105a2681b275fb3860c7a24f9f943be92c0 100644 (file)
@@ -11,18 +11,17 @@ all: io.o
 
 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)
 
@@ -38,5 +37,4 @@ misc/s390-misc.o: dummy
 net/s390-net.o: dummy
        $(MAKE) -C net
 
-
 include $(TOPDIR)/Rules.make
index 94d89876b69cfc19f4da5554afad34ee51462c2d..53ab87600e4d17365fdaf4949577e2caef549241 100644 (file)
@@ -2,7 +2,7 @@ all: s390-block.o
 
 CFLAGS += 
 O_TARGET := s390-block.o
-O_OBJS   :=         
+O_OBJS   := 
 M_OBJS   :=
 D_OBJS   :=
 
index 42107addd6077b8cee2ca08bdd90bd9b643de437..19557d0443401e796ff969484e7e921164a2f368 100644 (file)
@@ -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    
  * 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>
 #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>
 #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 do_dasd_request (void);
 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 @@ dasd_create_devreg ( int devno ) {
         }
         return r;
 }
-
 static void
 dasd_add_range (int from, int to)
 {
@@ -162,7 +183,7 @@ dasd_add_range (int from, int to)
         }  else {
                 range -> to = to;
         }
-
+        
         /* chain current range to end of list */
         if ( dasd_range_head == NULL ) {
                 dasd_range_head = range;
@@ -226,7 +247,7 @@ dasd_split_parm_string ( char * str )
                 count ++;
                 tmp = end;
         } while ( tmp != NULL && *tmp != '\0' );
-       }
+}
 
 static char dasd_parm_string[1024] = {0,};
 
@@ -239,12 +260,12 @@ dasd_setup (char *str)
                 *(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 @@ dasd_parse (char **str)
 {
        char *temp;
        int from, to;
-
+        
        if ( *str ) { 
         dasd_probeonly = 0;
        }
@@ -284,19 +305,19 @@ dasd_parse (char **str)
                 } 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_from_devno (int devno)
                        devindex += devno - temp -> from;
                        break;
                }
-               }
+       }
         if ( temp == NULL ) 
                 return -ENODEV;
        return devindex;
-               }
+}
 
 /* SECTION: ALl needed for multiple major numbers */
 
@@ -335,7 +356,7 @@ static major_info_t dasd_major_info[] =
 #endif /* LINUX_IS_24 */
                        nr_real:DASD_PER_MAJOR,
                }
-               }
+       }
 #if 0
         ,
        {
@@ -352,8 +373,8 @@ static major_info_t dasd_major_info[] =
                        max_nr:DASD_PER_MAJOR,
 #endif /* LINUX_IS_24 */
                        nr_real:DASD_PER_MAJOR,
-                       }
                }
+       }
 #endif
 };
 
@@ -361,7 +382,7 @@ static dasd_device_t *
 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 @@ static major_info_t *
 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 @@ static spinlock_t discipline_lock;
  * 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 @@ dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
 
 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 @@ dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
                if (prev->next == NULL)
                        q->tail = prev;
        }
-       cqr->next = NULL;
+/*     cqr->next = NULL; */
        q->queued_requests--;
        return 0;
 }
@@ -520,6 +541,8 @@ static spinlock_t cq_lock;          /* spinlock for cq_head */
 #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 dasd_chanq_t *qlist_head = NULL;           /* head of queue of queues */
 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 @@ qlist_enq (dasd_chanq_t * q)
 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 @@ qlist_deq (dasd_chanq_t * q)
                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 @@ qlist_deq (dasd_chanq_t * q)
        }
        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 @@ dasd_partn_detect (int devindex)
         resetup_one_dev(dd,minor>>DASD_PARTN_BITS);
 #endif /* LINUX_IS_24 */
        return rc;
-       }
+}
 
 /* SECTION: Managing wrappers for ccwcache */
 
@@ -623,8 +647,8 @@ dasd_init_emergency_req ( void )
         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 @@ dasd_alloc_request (char *magic, int cplength, int datasize)
                 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 @@ dasd_alloc_request (char *magic, int cplength, int datasize)
         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 @@ try_request_fn (void)
           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 @@ dasd_start_IO (ccw_req_t * cqr)
        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 @@ dasd_start_IO (ccw_req_t * cqr)
                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 @@ dasd_start_IO (ccw_req_t * cqr)
                          " 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 @@ do_dasd_request (void)
        major_info_t *major_info;
        int devno;
         int major;
-        
+
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
         {
@@ -894,34 +956,34 @@ do_dasd_request (void)
 #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 @@ dasd_do_chanq (void)
        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 @@ dasd_do_chanq (void)
                                        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 @@ dasd_do_chanq (void)
                                                                " 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 @@ dasd_do_chanq (void)
                                                                " 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 @@ dasd_do_chanq (void)
                                                                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_int_handler (int irq, void *ds, struct pt_regs *regs)
        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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
                            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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
                        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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
                         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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
                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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
                }
                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_int_handler (int irq, void *ds, struct pt_regs *regs)
        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 @@ default_erp_postaction (ccw_req_t * cqr, int success)
                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)"
-                       " 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);
+                        " 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)"
+                        " ...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 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
        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 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
                        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 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 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 @@ dasd_open (struct inode *inp, struct file *filp)
                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 @@ dasd_register_major (major_info_t * major_info)
        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 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
 
         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 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
                        return -EINVAL;
                } else {
                        len += sprintf (str + len, "%d", partition);
-       }
+               }
        }
        str[len] = '\0';
        return 0;
@@ -1976,25 +2168,40 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
 
 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_enable_single_volume ( int irq ) {
         }
         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 @@ dasd_oper_handler ( int irq, devreg_t *devreg ) {
                 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 @@ dasd_set_device_level (unsigned int irq, int desired_level,
        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 @@ dasd_set_device_level (unsigned int irq, int desired_level,
                         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 @@ dasd_set_device_level (unsigned int irq, int desired_level,
                                         if (temp->check_characteristics) {
                                                 if (temp->check_characteristics (device)) 
                                                         continue;
-       }
+                                        }
                                         discipline = temp;
                                         break;
                                 }
@@ -2119,17 +2326,25 @@ dasd_set_device_level (unsigned int irq, int desired_level,
                                        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_set_device_level (unsigned int irq, int desired_level,
                                                                                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 @@ dasd_set_device_level (unsigned int irq, int desired_level,
                        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 @@ dasd_set_device_level (unsigned int irq, int desired_level,
                }
        } 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 @@ static struct proc_dir_entry dasd_proc_root_entry =
 #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 @@ dasd_devices_open (struct inode* inode, struct file*  file )
                 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 @@ dasd_devices_open (struct inode* inode, struct file*  file )
                temp = temp->next;
        }
         info->len=len;
-       return rc;
+        return rc;
 }
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
@@ -2407,41 +2609,59 @@ dasd_devices_read (  struct  file *file, char*   user_buf,  size_t  user_len, lo
         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 @@ static struct inode_operations dasd_devices_inode_ops =
 #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 @@ dasd_proc_init (void)
                 proc_register(&dasd_proc_root_entry, dasd_devices_entry);
         }
 #endif /* LINUX_IS_24 */
+        return rc;
 }
 
 void
@@ -2506,15 +2728,13 @@ dasd_init (void)
         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 @@ dasd_init (void)
                } 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 @@ cleanup_dasd (void)
                                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 @@ cleanup_dasd (void)
                 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 @@ init_module ( void )
         int rc=0;
         return dasd_init(); 
         return rc;
-       }
+}
 
 void 
 cleanup_module ( void ) 
index b77e731f9094606c27aebf56bd6d3f50ba83ff79..bb063f304aff423a5f19d0a853f7decdcc17133e 100644 (file)
@@ -5,6 +5,5 @@ void dasd_int_handler (int , void *, struct pt_regs *);
 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 );
 
index 63d01f6601a5c0e8388c8d67ed53883d2a00f8af..963260f3f9c98bd135b48fb5c0171a563e99e25b 100644 (file)
@@ -64,13 +64,22 @@ dasd_era_t
 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) {
index 91a0448c7d785cdec0d40aaa036ed831ef4c9a97..afb82c4b6f3bef649ab98dbb40b313863a7cdf04 100644 (file)
@@ -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 @@ dia210 (void *devchar)
 {
        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 @@ dia250 (void *iob, int cmd)
 {
        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;
 }
 
@@ -535,6 +561,23 @@ dasd_diag_init( void ) {
         }
         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);
+          rc = -EINVAL;
+        }
+        return rc;
+}
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
index 3e18eba06cb2e09f70bc4e02f4edbac29f54c815..521a940710a4ca850ba1f0063203bb81fbc94800 100644 (file)
@@ -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"
 #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 @@ dasd_eckd_private_t {
         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 @@ recs_per_track (dasd_eckd_characteristics_t * rdc,
 {
        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 @@ recs_per_track (dasd_eckd_characteristics_t * rdc,
                } 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 @@ define_extent (ccw1_t * de_ccw,
        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 @@ define_extent (ccw1_t * de_ccw,
        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 @@ define_extent (ccw1_t * de_ccw,
                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 @@ locate_record (ccw1_t * lo_ccw,
               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 @@ locate_record (ccw1_t * lo_ccw,
                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 @@ locate_record (ccw1_t * lo_ccw,
 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 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device)
                 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 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device)
                 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 @@ dasd_eckd_init_analysis (struct dasd_device_t *device)
        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 @@ dasd_eckd_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
         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 @@ dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags)
        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;
         }
-        
-        if ( flags & 0x1 ) {
-          wrccws++;
-          datasize += sizeof(eckd_count_t);
+
+        /* 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 & 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 @@ dasd_eckd_examine_error  (ccw_req_t *cqr, devstat_t * stat)
            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 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req)
        /* 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 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req)
        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 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req)
                                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 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
                         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 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
                         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 @@ dasd_discipline_t dasd_eckd_discipline = {
 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;
 }
 
index 15d309d69f7ea46e8ce1972101cafa694d2bf181..c91963c42dfee9447f52f28c1451f5286160de39 100644 (file)
@@ -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_private_t {
         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 @@ dasd_fba_id_check ( dev_info_t *info )
                         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 @@ dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req)
        /* 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 @@ dasd_fba_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
         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 @@ dasd_discipline_t dasd_fba_discipline = {
         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.
index 8efca8eeea78e6664097c3d43b2feac838496595..db32ec9c6aaced67861a1c0562bfd961ec7b2ff3 100644 (file)
@@ -989,7 +989,7 @@ int xpram_init(void)
  fail_malloc:
        read_ahead[major] = 0;
        blk_dev[major].request_fn = NULL;
-       unregister_chrdev(major, "xpram");
+       unregister_blkdev(major, "xpram");
        return result;
 }
 
index 7c5b7589b7e9d5109d5033f09872bfc9ee1db65b..a4713da55119cb9380991d16227e72d927ad5d71 100644 (file)
@@ -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 @@ EXPORT_SYMBOL(ccw_free_request);
 
 /* 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 kmem_cache_t *ccw_cache[CCW_NUMBER_CACHES];
 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 @@ dechain ( ccw_req_t *request )
                }
        } else if ( request -> int_next || request -> int_prev ) {
        }
+       spin_unlock_irqrestore(&ccwchain_lock,flags);
        return;
 }
 
@@ -90,13 +95,14 @@ ccw_alloc_request ( char *magic, int cplength, int datasize )
        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 @@ ccw_alloc_request ( char *magic, int cplength, int datasize )
        /* 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 @@ ccw_alloc_request ( char *magic, int cplength, int datasize )
            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 @@ ccw_alloc_request ( char *magic, int cplength, int datasize )
        }
        /* 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 @@ ccw_alloc_request ( char *magic, int cplength, int datasize )
                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 @@ ccw_alloc_request ( char *magic, int cplength, int datasize )
                        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 @@ ccw_free_request ( ccw_req_t * request )
        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 @@ ccw_free_request ( ccw_req_t * request )
                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 @@ ccwcache_init (void)
        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 @@ ccwcache_cleanup (void)
                        }
                }
        }
-       debug_unregister( debug_area ,"ccwcache");
+       debug_unregister( debug_area );
 }
 
 #ifdef MODULE
index bfd9b95566d44cec0c2bef08f43f1bd1d01c6c27..c8ac10dfea0553070a261a0cf012587ff9f77963 100644 (file)
@@ -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 @@ typedef struct _raw3215_info {
        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 @@ static int tty3215_refcount;
 #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 @@ static void raw3215_mk_read_req(raw3215_info *raw)
         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_read_req(raw3215_info *raw)
  */
 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 @@ static void raw3215_mk_write_req(raw3215_info *raw)
                 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 @@ static void raw3215_mk_write_req(raw3215_info *raw)
                        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 @@ extern inline void raw3215_try_io(raw3215_info *raw)
                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 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                         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 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                } 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 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                 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,17 +548,45 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                         }
                         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
  */
@@ -569,16 +605,7 @@ raw3215_write(raw3215_info *raw, const char *str,
                                             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 @@ raw3215_write(raw3215_info *raw, const char *str,
                                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 @@ raw3215_write(raw3215_info *raw, const char *str,
                                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 @@ raw3215_write(raw3215_info *raw, const char *str,
                }
                 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 @@ raw3215_write(raw3215_info *raw, const char *str,
 /*
  * 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 @@ static int raw3215_startup(raw3215_info *raw)
        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 @@ raw3215_find_dev(int number)
         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 @@ int con3215_activate(void)
         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 @@ static void
 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 @@ void con3215_unblank(void)
 
        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 @@ static int tty3215_write_room(struct tty_struct *tty)
        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 @@ static int tty3215_write(struct tty_struct * tty, int from_user,
                    const unsigned char *buf, int count)
 {
        raw3215_info *raw;
-       int ret;
+       int ret = 0;
                                
        if (!tty)
                return 0;
@@ -1062,8 +1107,8 @@ __initfunc (long con3215_init(long kmem_start, long kmem_end))
        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;
index 2ed34ce04288221a06e16cca1b53286582029341..ed46a4a85a3000e42105134d74d4d9db6877e39d 100644 (file)
@@ -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 @@ typedef struct {
 
 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 @@ mto_t;
 
 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 write_hwcb_t write_hwcb_template =
 
 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 @@ read_hwcb_t;
 static read_hwcb_t read_hwcb_template =
 {
        PAGE_SIZE,
-       0x00,           
+       0x00,
        {
-               0x00,   
-               0x00,   
-               0x80    
+               0x00,
+               0x00,
+               0x80
        }
 };
 
-#endif   /* __HWC_H__ */ 
+#endif                         /* __HWC_H__ */
index ca46ad7c8181466b2c0af71282738f0a5174aeca..39b8444b68bc1b3042ae9167da9c83b728b8e77b 100644 (file)
 
 #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 @@ struct console hwc_console =
        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_console_unblank (void)
        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 !");
 
index c2de696c5a074aaf39480f94f274456c33afcd46..07a0ea50a3b3a53d2e4458d7f73d05890e0f8da8 100644 (file)
@@ -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 @@ hwcb_list_t;
 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 @@ static struct {
 {
        {
        },
-       {               
-               8,              
-               0,              
-               80,             
-               CODE_ASCII,     
-               1,              
-               50,             
-               MAX_KMEM_PAGES, 
+       {
+               8,
+                   0,
+                   80,
+                   CODE_ASCII,
+                   1,
+                   50,
+                   MAX_KMEM_PAGES,
 
-               0,              
+                   0,
 
-               0x6c            
+                   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 @@ static unsigned char psw_mask __attribute__ ((aligned (8)));
 #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 @@ internal_print (char write_time, char *fmt,...)
        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 @@ hwc_printk (const char *fmt,...)
        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 @@ dump_storage_area (unsigned char *area, unsigned short int count)
 
        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__ ("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__ ("IPM %0 \n\t"
+                             "SRL %0, 28 \n\t"
+                             :"=r" (condition_code));
 
        return condition_code;
 }
@@ -324,8 +329,8 @@ ext_int_param (void)
 {
        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 @@ prepare_write_hwcb (void)
 
        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 @@ sane_write_hwcb (void)
 
        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 @@ sane_write_hwcb (void)
                        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 @@ reuse_write_hwcb (void)
        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 @@ reuse_write_hwcb (void)
        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 @@ allocate_write_hwcb (void)
 {
        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 @@ allocate_write_hwcb (void)
 
        if (!OUT_HWCB)
                OUT_HWCB = page;
-       else    
+       else
                BUF_HWCB_NEXT = page;
 
        BUF_HWCB = page;
@@ -535,7 +540,7 @@ allocate_write_hwcb (void)
 
        hwc_data.hwcb_count++;
 
-       prepare_write_hwcb();
+       prepare_write_hwcb ();
 
        BUF_HWCB_TIMES_LOST = 0;
        BUF_HWCB_MTO_LOST = 0;
@@ -543,13 +548,13 @@ allocate_write_hwcb (void)
 
 #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 @@ release_write_hwcb (void)
 {
        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) {
-
-/*      memset((void *) page, 0, PAGE_SIZE); */
-
-                        page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
-                        clear_bit(page_nr, &hwc_data.kmem_pages);
+               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) {
+                       /*memset((void *) page, 0, PAGE_SIZE); */
+
+                       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 @@ add_mto (
        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 @@ write_event_data_1 (void)
 
        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 @@ static void
 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 @@ write_event_data_2 (void)
 #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 @@ write_event_data_2 (void)
 
 #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 @@ write_event_data_2 (void)
        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 (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");
+       if (add_mto (message, count) != count) {
+
+               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");
 #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 @@ set_alarm (void)
        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 @@ do_hwc_write (
        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 @@ do_hwc_write (
                        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 @@ do_hwc_write (
 
                        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 @@ do_hwc_write (
 
                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 @@ do_hwc_write (
                                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 @@ hwc_write (int from_user, const unsigned char *msg, unsigned int count)
 {
        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 @@ hwc_chars_in_buffer (unsigned char flag)
        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 @@ nr_setbits (kmem_pages_t arg)
        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 @@ hwc_write_room (unsigned char flag)
        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 @@ hwc_flush_buffer (unsigned char flag)
 {
        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 @@ seperate_cases (unsigned char *buf, unsigned short int count)
 
                                i_out++;
 
-                               i_in++; 
+                               i_in++;
 
                        } else
                                _case = ~_case;
@@ -1179,7 +1192,7 @@ seperate_cases (unsigned char *buf, unsigned short int count)
 
                        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 @@ gds_vector_name (u16 id, unsigned char name[])
        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 @@ find_gds_vector (
        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 @@ find_gds_vector (
 
 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 @@ find_gds_subvector (
        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 @@ get_input (void *start, void *end)
        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 @@ eval_selfdeftextmsg (gds_subvector_t * start, void *end)
        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 @@ eval_textcmd (gds_subvector_t * start, void *end)
        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 @@ eval_cpmsu (gds_vector_t * start, void *end)
        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 @@ eval_mdsmu (gds_vector_t * start, void *end)
        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 @@ eval_evbuf (gds_vector_t * start, void *end)
        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 @@ process_evbufs (void *start, void *end)
        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 @@ unconditional_read_1 (void)
        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 @@ unconditional_read_2 (void)
 {
        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 @@ unconditional_read_2 (void)
                                       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 @@ write_event_mask_1 (void)
 {
        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 @@ write_event_mask_2 (void)
 
        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 @@ write_event_mask_2 (void)
            (!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 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
 {
        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 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
                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 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
                        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 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
                        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 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
                        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 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
        }
        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 @@ hwc_init (unsigned long *kmem_start)
        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_init (unsigned long *kmem_start)
                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 @@ hwc_init (unsigned long *kmem_start)
 
        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 @@ do_hwc_interrupt (struct pt_regs *regs, __u16 code)
                                        " 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 @@ hwc_unblank (void)
 {
 
        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 @@ hwc_ioctl (unsigned int cmd, unsigned long arg)
        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 @@ hwc_ioctl (unsigned int cmd, unsigned long arg)
                        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;
 }
index bd72a591fbb9ad769fefa763f87f20e544a91e86..6ef3b23ebeaad6a08d6aff7c27d5c85a615ebab6 100644 (file)
@@ -31,6 +31,7 @@ typedef signed char ioctl_nl_t;
 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 @@ typedef struct {
        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 @@ static hwc_ioctls_t _hwc_ioctls;
 
 #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 @@ static hwc_ioctls_t _hwc_ioctls;
 
 #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 @@ extern signed int hwc_unregister_calls (hwc_high_level_calls_t *);
 
 #endif
 
-#endif   
+#endif
index d32cad5ef2483179ef09178289d6872efc5e2cf3..488058d959130ab6e54a52ea8bc058bd816a5a1d 100644 (file)
@@ -43,22 +43,22 @@ typedef struct {
 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 @@ hwc_tty_open (struct tty_struct *tty,
 
 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 @@ hwc_tty_write_room (struct tty_struct *tty)
 {
        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 @@ hwc_tty_flush_chars (struct tty_struct *tty)
 {
        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 @@ hwc_tty_chars_in_buffer (struct tty_struct *tty)
 {
        int retval;
 
-       retval = hwc_chars_in_buffer(IN_BUFS_TOTAL);
+       retval = hwc_chars_in_buffer (IN_BUFS_TOTAL);
        return retval;
 }
 
@@ -159,15 +159,15 @@ hwc_tty_flush_buffer (struct tty_struct *tty)
 
 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 @@ hwc_tty_ioctl (
                                     (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_input (unsigned char *buf, unsigned int count)
                             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 @@ hwc_tty_input (unsigned char *buf, unsigned int count)
                                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 @@ hwc_tty_input (unsigned char *buf, unsigned int count)
 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_init (void)
        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_init (void)
        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 --git a/drivers/s390/idals.c b/drivers/s390/idals.c
new file mode 100644 (file)
index 0000000..cd81d8f
--- /dev/null
@@ -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;
+                       }
+               }
+       }
+
+}
index 2c2a182b66baf4b4e8f48c5b547adb2ce5a1776f..4d4dbb54bf1478438bca4be92b0a5779016b3cae 100644 (file)
@@ -7,6 +7,10 @@ M_OBJS   :=
 
 ifeq ($(CONFIG_CTC),y)
   O_OBJS += ctc.o
+else
+  ifeq ($(CONFIG_CTC),m)
+  M_OBJS += ctc.o
+  endif
 endif
 
 ifeq ($(CONFIG_IUCV),y)
index 1b7580ad98129ecca8db904bd3a91719740840e1..9a828e26216994bed5bf3c065c0312b32fe14797 100644 (file)
@@ -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
  *    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
  *
- *  Change History
+ * 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.
+ *
+ *
+ * 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>
 #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>
 #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        
-#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 @@ typedef enum {
  *
  */  
 
-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 @@ static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS];  /* 0 = CTC
  */
     
 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 @@ struct ctc_priv {
 
 #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__ int ctc_check_busy(net_device *dev)
 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__ int ctc_check_busy(net_device *dev)
 
 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 @@ static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev)
 
 /* 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 @@ int ctc_probe(net_device *dev);
  
 
 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);
@@ -369,36 +480,56 @@ static channel_type_t channel_check_for_type (senseid_t *id);
 static void channel_sort(struct devicelist list[], int n);
 
 
+/*
+ * 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_init(void)
 */  
 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 void channel_scan(void)
  */  
 static int channel_free(int media, int devno)
 {
-        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; 
+       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; 
 }
 
 
@@ -465,17 +595,17 @@ static int channel_free(int media, int devno)
  */  
 static int channel_get(int media, int devno)
 {
-        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; 
+       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; 
 
 }
 
@@ -485,18 +615,18 @@ static int channel_get(int media, int devno)
  */  
 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_get_next(int media)
  */  
 static int channel_left(int media)
 {
-        return channel[media].left; 
+       return channel[media].left; 
 }
 
 
@@ -514,38 +644,38 @@ static int channel_left(int media)
  */
 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; 
+                       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 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;
-
-                default:
-                        type = channel_type_none;
-
-        }
-        return type;
+                               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;
+
+       }
+       return type;
 }
 
 
@@ -554,22 +684,22 @@ static channel_type_t channel_check_for_type (senseid_t *id)
  */
 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 void channel_sort(struct devicelist list[], int n)
 
 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;
-
-           
-        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;
+       
+       struct buffer    *p;
+
+          
+       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; 
+       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(DEBUG "%s: protocol=%x read=%04x write=%04x\n",
-             dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
-#endif  
-        ctc_setup_return;
-        
+       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 @@ __setup("ctc=", ctc_setup);
 
 /*
  *   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;   
-
-        return 0;
+{      
+       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;
 } 
 
 
@@ -867,456 +1060,563 @@ int ctc_probe(net_device *dev)
  *
  */
 
-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);
+               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: 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);
-        }
+       } 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;
-                        }
-
-                        if(!devstat->flag & DEVSTAT_FINAL_STATUS)
-                                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; 
                        ctc_protect_busy(dev);
                        ctc_clearbit_busy(TB_RETRY,dev);
                        ctc_unprotect_busy(dev);
-                        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-
-                        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);    
+                       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);
+                               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);
+                       }
+                       
+                       if (test_and_set_bit(CTC_BH_ACTIVE, &ctc->flag_a) == 0) {
+                               queue_task(&ctc->tq, &tq_immediate);
+                               mark_bh(IMMEDIATE_BH);
+                       }
+                       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);
+                                       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;
+                               }
+                               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;
+               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);
+                               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) {  
+                       } 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); 
+                               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);
+                               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); 
+                                       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;
-                                }
-                        
-
-                        clear_bit(0, (void *)&ctc->IO_active);              /* set by ctc_tx or ctc_bh */
-                        return;
+                                       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, &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;
-
-        dev = (net_device *) ctc->dev; 
-        privptr = (struct ctc_priv *) dev->priv; 
+       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;
+
    
 #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;
-                }
-                }
-
-                s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-
-                if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) {
+       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, dev);
+
+               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 void ctc_write_retry (struct channel *ctc)
  */
 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)
+static void ctc_timer (unsigned long data)
 {
+       struct channel *ctc = (struct channel *) data;
 #ifdef DEBUG
-        net_device  *dev;
-
-        dev = (net_device *) ctc->dev; 
-        printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
+       net_device *dev = (net_device *) ctc->dev; 
+       printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
 #endif
-        ctc->flag |= CTC_TIMER;
-        wake_up(&ctc->wait);  
-        return;
+       ctc->flag |= (CTC_TIMER|CTC_WAKEUP);
+       wake_up(&ctc->wait);  
+       return;
 }  
 
 /*
@@ -1452,49 +1768,75 @@ static void ctc_timer (struct channel *ctc)
  */
 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;
-        }
-
-        return 0;
+       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;
+       }
+
+       MOD_DEC_USE_COUNT;
+       return 0;
 }  
 
 
@@ -1505,80 +1847,80 @@ static int ctc_release(net_device *dev)
  */
 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);
-
-        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;
+       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;
                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 @@ Done:
  *   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 @@ static int ctc_change_mtu(net_device *dev, int new_mtu)
  */
 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 --- */
index fcac4037c8fe50b45a4efb509e2670b1b43502b1..e6c12b8e0acf2a2ce57a238c2a45e05c62e2294a 100644 (file)
@@ -9,7 +9,7 @@
  * 
  *    \r
  *    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)\r
  *                Alan Altmark (Alan_Altmark@us.ibm.com)
  *                
 
@@ -504,12 +504,15 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
   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 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
       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;
index 4fc640297b004a7e96605de826aba138701402b7..cb7156446e43bcd6ecc00339e54e46a41de1ab38 100644 (file)
@@ -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>
  * 
  */
 
  * 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.
 #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 @@ static void envtrl_i2c_test_pin(void)
        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 @@ static int envctrl_i2c_fan_status(struct i2c_child_t *pchild,
        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 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos)
                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 @@ envctrl_ioctl(struct inode *inode, struct file *file,
        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 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
 
        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 @@ static void envctrl_init_fanstat(struct i2c_child_t *pchild)
        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 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
                }
        }
 
+       /* 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 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
                        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;
@@ -942,6 +1047,18 @@ done:
                       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;
 #else
        return -ENODEV;
index e30bb608c5da2bbb0a804b2320b13d9bd2584b09..1ccc277e0d7a8d4d4536456c2f975611c3b3989f 100644 (file)
@@ -62,12 +62,18 @@ struct awacs_regs {
 #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 */
index 084de211e520c81d91af01638fb3fa74001ce350..3369df47e7cb7f7c7120e89c18ad77e88ccdc942 100644 (file)
@@ -179,6 +179,9 @@ static int awacs_spkr_vol;
 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 @@ static volatile struct dbdma_cmd *awacs_tx_cmds;
  * 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 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
                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 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
                        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 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
                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 @@ void __init dmasound_init(void)
                                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 @@ void __init dmasound_init(void)
                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 =
index 13bf863a041e1129e66db177002d3328a49eb3e4..a6e46f600c000fdd72582b114792fd48f4ec41e1 100644 (file)
@@ -49,6 +49,7 @@ comment 'USB Devices'
          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
index 6bb1123875a08b69784d820f68960639e1470542..45eaa9e8a8f77de28581c65b7789bb640a9484ab 100644 (file)
@@ -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 @@ static unsigned short x86_keycodes[256] = {
        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; 
 
@@ -92,28 +129,6 @@ static int emulate_raw(unsigned int keycode, int 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;
-}
-
 #endif
 
 static struct input_handler keybdev_handler;
index 6632b6c9a307fb16660d5717a41633790ba1ab11..c262023a7b7f6f9b2da3db9b799480d986b1f5c1 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)          += keyspan_pda.o
 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 --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
new file mode 100644 (file)
index 0000000..c56dbf6
--- /dev/null
@@ -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 --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
new file mode 100644 (file)
index 0000000..ee36038
--- /dev/null
@@ -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 */
+
index 2a340c4bd31f4a2f026519268fa9252da81cf595..94e4eb92e6d212bcd71d8c5436706d0118371aec 100644 (file)
 
 #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 @@ static int sohci_unlink_urb (urb_t * urb)
                        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 @@ static int sohci_unlink_urb (urb_t * urb)
                        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 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
        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 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                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 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                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 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                                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 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                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 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                                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 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int i
        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 @@ static void td_submit_urb (urb_t * urb)
                                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 @@ static void td_submit_urb (urb_t * urb)
                        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 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
        }
   
        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 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
        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 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
        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 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
 {
        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 int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
 }
 
 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 @@ static int __init ohci_hcd_init (void)
 {
        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  
index 3ac5dafb24cb26947afb0908498bf93f4718815f..806be5255589a7e94f01c21270f59ae368b1ec4b 100644 (file)
@@ -410,6 +410,7 @@ typedef struct ohci {
        struct usb_bus * bus;    
        struct usb_device * dev[128];
        struct virt_root_hub rh;
+       struct pci_dev *pci_dev;
 } ohci_t;
 
 
index a01b99e031eb0ac2b5bdc8a7521ccad5105bffbd..c475b19522d3b6f729f1070e3ce03f9cfd9e0b61 100644 (file)
 #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
 
 #define PLL_WR_EN                              0x00000080
 
+/* PLL registers */
 #define CLK_PIN_CNTL                           0x0001
 #define PPLL_CNTL                              0x0002
 #define PPLL_REF_DIV                           0x0003
 #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
 #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
 #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 */
index 329a3d51ef26463c49e3d22f32e47065cba09b60..c7de4a3ea6b4185e888c8b87bf33c873a1d131da 100644 (file)
@@ -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 fb_info_aty128 {
     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 @@ struct fb_info_aty128 {
 
 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 @@ static int aty128_decode_var(struct fb_var_screeninfo *var,
                              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 @@ static struct fb_ops aty128fb_ops = {
     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 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
 #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 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
     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 @@ unmap_out:
 }
 #endif /* ! CONFIG_FB_OF */
 
+#ifndef CONFIG_FB_OF
 static int __init
 aty128find_ROM(struct fb_info_aty128 *info)
 {
@@ -1970,6 +2008,7 @@ aty128find_ROM(struct fb_info_aty128 *info)
 #endif /* !CONFIG_PPC */
     return (flag);
 }
+#endif /* CONFIG_FB_OF */
 
 #ifndef CONFIG_PPC
 static void __init
@@ -2051,13 +2090,10 @@ aty128fb_of_init(struct device_node *dp)
     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 @@ aty128fbcon_blank(int blank, struct fb_info *fb)
     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 @@ aty128fbcon_blank(int blank, struct fb_info *fb)
        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 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
         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 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
         }
 
         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 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     /* 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 @@ aty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     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 @@ do_install_cmap(int con, struct fb_info *info)
     }
 }
 
+#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 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
     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 */
 
 
     /*
index 26910e67e24aa22dc60839d29ebc2a2d4aac3274..df78ab300081c633e53e8b7d9756cda4d5ebc89a 100644 (file)
@@ -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 @@ struct fb_info_aty {
 #endif
 #ifdef CONFIG_PMAC_PBOOK
     unsigned char *save_framebuffer;
-    unsigned long save_pll[64];
     struct fb_info_aty* next;
 #endif
 };
@@ -412,6 +412,16 @@ static struct fb_ops atyfb_ops = {
 #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 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
        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 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
 
 #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 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
 
 #if defined(CONFIG_PPC)
     if ((_machine == _MACH_Pmac) && !blank)
-       pmu_enable_backlight(1);
+       set_backlight_enable(1);
 #endif
 }
 
@@ -4215,6 +4227,38 @@ aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
 }
 #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 u32 vram = 0;
 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
 
index be1d8bc7c19d19d3bdf5cf075e3fad2e8bd9ef40..ebda21258e262baa05cd210d29e383a79bcf9cd4 100644 (file)
@@ -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 @@ static void chipsfb_blank(int blank, struct fb_info *info)
        // 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 @@ static void chipsfb_blank(int blank, struct fb_info *info)
                        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 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
        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 @@ __initfunc(void chips_of_init(struct device_node *dp))
        memset(p->frame_buffer, 0, 0x100000);
 
        /* turn on the backlight */
-       pmu_enable_backlight(1);
+       set_backlight_enable(1);
 
        init_chips(p);
 }
index 52187b1411f6930dfac71fe4b20d012a95ebbde4..19dfda72f00c66b1b3eb7d79c5fd0f8cd4e64a66 100644 (file)
@@ -48,7 +48,8 @@ enum {
        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 @@ __initfunc(void offb_init(void))
        /* 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 @@ __initfunc(void offb_init(void))
 
     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 @@ __initfunc(static int offb_init_driver(struct device_node *dp))
 {
 #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 @@ __initfunc(static void offb_init_fb(const char *name, const char *full_name,
                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 @@ __initfunc(static void offb_init_fb(const char *name, const char *full_name,
                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 @@ static void offbcon_blank(int blank, struct fb_info *info)
                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 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        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)
index 53721ceff92ebebc611ddb5cfe66482b6afc9672..b3b1c4eede8fb418ea04dcb49dc49563a2aa70c4 100644 (file)
@@ -78,6 +78,7 @@ if [ "$CONFIG_INET" = "y" ]; then
   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
index e5ab7e47328bd5151b3222f8494a72b1d9e89c17..d2cde719a1709b0b0ce8d4427063a9aa7621d967 100644 (file)
@@ -76,9 +76,11 @@ nfsd_svc(unsigned short port, int nrservs)
        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 */
 
index 75ddf916e8d6d6bf7ef615fbf1ad5e73507534bf..98c7ec7b7a0127cffc841a36d19d1ce7ed924b72 100644 (file)
@@ -295,8 +295,8 @@ static int get_kstat(char * buffer)
                 "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 @@ static int get_kstat(char * buffer)
 #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 @@ static int get_status(int pid, char * buffer)
 {
        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 @@ static int get_status(int pid, char * buffer)
        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 --git a/include/asm-ppc/backlight.h b/include/asm-ppc/backlight.h
new file mode 100644 (file)
index 0000000..79756ec
--- /dev/null
@@ -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
index 4283ab26b886c1ee94d87a058afe7f603ed74979..ab1b0b54648a9c096005319bfcc53b099664cf7e 100644 (file)
  * 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 @@ extern __inline__ void __delay(unsigned int loops)
                                     "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) */
index 3e980e3531a435dbb24c573441d50c4a5865a36b..1ef9326de0eecaf8ab85e1cbfec549f0ff76e4b4 100644 (file)
@@ -203,6 +203,7 @@ static __inline__ void enable_dma(unsigned int dmanr)
         */
        unsigned char ucDmaCmd=0x00;
 
+#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
        if(_prep_type==_PREP_Radstone)
        {
                switch(ucSystemType)
@@ -227,6 +228,7 @@ static __inline__ void enable_dma(unsigned int dmanr)
                        }
                }
        }
+#endif /* CONFIG_PREP || CONFIG_ALL_PPC */
 
        if (dmanr != 4)
        {
index 78d73b5327bdccd56e4adb934465c32a85c03c98..9d96c8062d43b2773ec848450bdc09032a735b9c 100644 (file)
@@ -45,6 +45,7 @@ enum system_feature {
        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 @@ extern int   feature_clear(struct device_node* device, enum system_feature f);
 /* 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 */
index 647c63261592e26e818141bd63e0bfc5db18f15c..cefda9144ae85dc8a3462141439c12c18d87946a 100644 (file)
 #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 */
+
index 537f402f820ee058bfc46ae813b7eade9fb8b6f0..d1c0d9743b39f34f91c167bc82832e00225a607b 100644 (file)
@@ -31,8 +31,6 @@ extern void enable_irq(unsigned int);
 #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
index f5c5bc97b9153a2064794d6d6e9269709e6816b4..3fe4cb0f8d1e1169013c96acab932ab1c8bff1f2 100644 (file)
@@ -71,8 +71,8 @@ static inline void kbd_init_hw(void)
                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 --git a/include/asm-ppc/keylargo.h b/include/asm-ppc/keylargo.h
new file mode 100644 (file)
index 0000000..2e7cb62
--- /dev/null
@@ -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))
+
index 42b8ceeec07933b282863acd0109ad7fd9da215d..dc9cbc425f18ea126d7714826109ea13b684d204 100644 (file)
@@ -30,7 +30,7 @@ struct machdep_calls {
        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 @@ struct machdep_calls {
        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 @@ struct machdep_calls {
        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;
index 2e61bb8f44cd1de3a4bca3ec4ae7f67a4bc2f34b..3b1fdda58b62af57fd2f46c2b2dfea388f6bf7ab 100644 (file)
@@ -38,6 +38,8 @@ enum {
        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 int  pmac_get_partition(int partition);
 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
index e3f3c15909b0392a23b3938f84825f10edbd5b6b..90a4398d93f7b8975c257aed8c73df0d70f28938 100644 (file)
@@ -6,9 +6,26 @@ unsigned long pmac_find_bridges(unsigned long, unsigned long);
 /*
  * 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 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
 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 --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
new file mode 100644 (file)
index 0000000..8b7b829
--- /dev/null
@@ -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
index 96169f65f455d81de45c092b576e1f3abde87768..cc75f64e2e29871393ad2775e0c99641eca59a69 100644 (file)
@@ -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 */
 #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 @@ enum {
 
 /* 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 @@ enum {
 
 #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 @@ struct pmu_sleep_notifier
 #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 */
index ece592e173e2ab2a1db2bc5996d127a41e39c714..efa70cb57094be00e9190d449419fd2905fddae3 100644 (file)
 #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)
index a3b799e0ffc0c8ce9e814e2363d6e06101a27cf3..3d838e24d534dd2d520fe6ecafe37ae0ac3725d9 100644 (file)
@@ -32,13 +32,6 @@ extern void xmon(struct pt_regs *excp);
        __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 void poweroff_now(void);
 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);
index fd77878bf8a7460ec36d8703cdbf2db49d123483..dd166b078ad9eba60b73ab38a13f3664777fad95 100644 (file)
@@ -57,7 +57,7 @@ struct exception_table_entry
 
 /* 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
index 12d444cb1fe9beb4c249edaa55a52f192624c561..f18b5c7f31f669d757e5ca8e802bafe8230daadc 100644 (file)
@@ -7,6 +7,7 @@ struct ucontext {
        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 --git a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h
new file mode 100644 (file)
index 0000000..9b05cd2
--- /dev/null
@@ -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
+
+
+
index 3fa95e840cca2ac5a9e521544483049847e8ea8b..a3733a1771c275e61132c53b740b68c7b097e615 100644 (file)
 #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
 
index a0312f958612c409a153c708ac3eeeb079effe03..bc47df7fc4e2f4871efc1a6296255d4279713729 100644 (file)
@@ -29,8 +29,8 @@ static __inline__ int atomic_read(atomic_t *v)
 {
         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_set(atomic_t *v, int i)
 
 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 @@ atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
         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 @@ static __inline__ void
 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 @@ atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
 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;
 }
 
index b852baeea70d426354de9561a5792545d9c2d87d..b8cc1919d4fe9de1d9ce6c1aaab3bb859665014d 100644 (file)
@@ -737,24 +737,24 @@ extern int __inline__ ffs (int x)
           return 0;
         __asm__("    lr   %%r1,%1\n"
                 "    sr   %0,%0\n"
-                "    tmh  %%r1,0xFFFF\n"
-                "    j  0f\n"
+                "    tml  %%r1,0xFFFF\n"
+                "    jnz  0f\n"
                 "    ahi  %0,16\n"
                 "    srl  %%r1,16\n"
-                "0:  tml  %%r1,0xFF00\n"
-                "    j  1f\n"
+                "0:  tml  %%r1,0x00FF\n"
+                "    jnz  1f\n"
                 "    ahi  %0,8\n"
                 "    srl  %%r1,8\n"
-                "1:  tml  %%r1,0x00F0\n"
-                "    j  2f\n"
+                "1:  tml  %%r1,0x000F\n"
+                "    jnz  2f\n"
                 "    ahi  %0,4\n"
                 "    srl  %%r1,4\n"
-                "2:  tml  %%r1,0x000C\n"
-                "    j  3f\n"
+                "2:  tml  %%r1,0x0003\n"
+                "    jnz  3f\n"
                 "    ahi  %0,2\n"
                 "    srl  %%r1,2\n"
-                "3:  tml  %%r1,0x0002\n"
-                "    j  4f\n"
+                "3:  tml  %%r1,0x0001\n"
+                "    jnz  4f\n"
                 "    ahi  %0,1\n"
                 "4:"
                 : "=&d" (r) : "d" (x) : "cc", "1" );
index 477f79433f818ced33f9ef446a78ce598a0f9f33..ffbd4baeb9300bbb840d6cd89cbcd22b54dfcc4d 100644 (file)
@@ -57,13 +57,14 @@ typedef struct ccw_req_t {
 /* 
  * 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 :\
index 487ccc99bf2ec40fcd12d57434f38f0cf9ed8b1c..35e249facda40a29a93c6c847ae2d4b45278b956 100644 (file)
@@ -92,7 +92,7 @@ csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum
  *      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 @@ csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
                    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;
 }
index 2678fbd3dc3733406953cea58aeb573fbd39de63..0c5b942746cd1bf8916149df0e68db1a3067ab6a 100644 (file)
@@ -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>
index 48f40cb5628a154e98e32095b78afaeb1df8407d..ec722074811f673a792512e30375eb0b9edb9485 100644 (file)
+/*
+ *  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
 
+#ifdef __KERNEL__
+
 #include <asm/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
 
-#ifdef __KERNEL__
+#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);
 
-#define MAX_DEBUG_AREAS 16
-
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
-
-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 --git a/include/asm-s390/idals.h b/include/asm-s390/idals.h
new file mode 100644 (file)
index 0000000..362e91d
--- /dev/null
@@ -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 );
+
index d641cacffa4e88b3f914682e61d6640ce296e21f..afdb43a3a119d2919f1c7945577498ffcc09c305 100644 (file)
@@ -22,7 +22,7 @@ extern int enable_irq(unsigned int);
  * 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 @@ struct hw_interrupt_type {
  * 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 @@ typedef struct {
 #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 @@ typedef struct {
 #define CCW_CMD_SENSE_ID        0xE4
 
 #ifdef __KERNEL__
-
 #define SENSE_MAX_COUNT         0x20
 
 /*
@@ -192,101 +188,100 @@ typedef struct {
  * 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 union {
 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 _ciw {
 //
 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 {
  */
 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 @@ typedef struct {
 #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 @@ struct s390_irqaction {
        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 @@ typedef struct {
 #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 @@ typedef struct {
  */
 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 get_irq_next ( int irq );
 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 @@ extern __inline__ int iac( void)
         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 @@ void unmask_irq(unsigned int irq);
 
 extern spinlock_t irq_controller_lock;
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 
 #include <asm/atomic.h>
 
@@ -779,28 +784,27 @@ static inline void irq_exit(int cpu, unsigned int irq)
 
 #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 @@ static inline void s390_do_profile (unsigned long addr)
 
 #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
 
index f52f3513ff59982bbf1b5e03c2f6e066209e9516..23304b92058c24fdbac8a34178fcb9729c06e394 100644 (file)
@@ -130,7 +130,7 @@ struct _lowcore
        __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 */
index c78d97b43243591175d0c3e2ef46f27629974f48..429b3a4f4b57bfa4925fcd4d8141e245ae9c9852 100644 (file)
 
 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 *);
@@ -46,3 +46,6 @@ extern __u64  __extendsfdf2(__u32);
 
 #endif                                 /* __MATHEMU__                      */
 
+
+
+
index c33fcfef42de10defa1a7614bb716099534affd8..63166d18df07aff52ba33e92b108fe6f953ca733 100644 (file)
@@ -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 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 }
 
 #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 @@ static inline void flush_tlb_range(struct mm_struct * mm,
  * 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 @@ extern pte_t * __bad_pagetable(void);
 
 #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));         \
index 8c7651a7d9709d90a638ba78c42de47d0197da12..5a0abe6af35cb214fdf67986989057dd5c4999d7 100644 (file)
@@ -90,7 +90,7 @@ typedef struct thread_struct thread_struct;
 
 #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}, \
index 5a07956651d13224f28a31627489172415375c5d..5dbe10840fd1770103143b1d181290cf6e97defc 100644 (file)
@@ -145,12 +145,8 @@ typedef struct pt_regs pt_regs;
 #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
 
 
index aabd220725bcff11041af7c48416d995d93b646e..f3c313b7c60f3e0602675e27b9d8cf502ca99a38 100644 (file)
@@ -69,10 +69,14 @@ typedef struct
        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))
+
 
 
 /*
index 31f76b81e0bbd96fa229cb365d5c6c89ac307b7f..d9aae91e1b320d0670b9fd0037cea127acff8e94 100644 (file)
@@ -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)
  */
 
index 570b24e0b8c92d902d26feac38ab4d4e020246d1..435261bc2c62fa7cfdb46341f6f5374d50b5e6eb 100644 (file)
@@ -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 !
index 75fb3b4ff08ff1d93ff82d069819e0baa57c3194..7436895795852b242e59a9ad5f61799b2625d588 100644 (file)
@@ -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 @@ typedef struct _crw {
 #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
index fdf15d2dad0b9b0cd8781b3d2a5224b52741b871..25c65e26a85f1f661373e03b6ac2028ce403025c 100644 (file)
@@ -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
 #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;
 };
 
 
index 62e02dfa36e080d3f15808a1caeb5d4d1b3107bc..f047c6ba93433886e06f70a778a8a60de9c9e18a 100644 (file)
@@ -150,6 +150,7 @@ typedef enum
        ec_get_ctl,
        ec_set_ctl_masked,
         ec_ptlb,
+        ec_callback,
         ec_cmd_last
 } ec_cmd_sig;
 
@@ -187,6 +188,13 @@ typedef struct
        __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
  */
@@ -250,6 +258,8 @@ signal_processor_ps(__u32 *statusptr, __u32 parameter,
    return ccode;
 }
 
+extern void smp_do_callback_all(void (*callback)(void *), void *data);
+
 #endif __SIGP__
 
 
index f0a2530292db4d29a0fc22f77bb0ede96147043f..df2a068b17ad756ae32d47e017c6c794b5db1f6c 100644 (file)
@@ -97,9 +97,9 @@ extern inline void spin_lock(spinlock_t *lp)
         __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" );
 }
 
index 60bed008f9bf8c02fa58330511bda107ce622f63..bdcfe8b04bebb9e2a221fb9f9f9908c7b3700430 100644 (file)
@@ -31,7 +31,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                         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 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "   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 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                         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 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "   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 int save_fp_regs1(s390_fp_regs *fpregs);
 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 {                                       \
index 0175f18cd301623d6e82bf094e60a8d568b70dbc..0c8131e52ee37eca93517cff5eb9dbdf9f43c468 100644 (file)
@@ -89,7 +89,7 @@ struct termio {
         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); \
 })
 
 /*
index 09ce0f321d650d3d5a68f95c3bf057878954bed7..5960c243c667ca0f77e0c8d856ca3bcc549008e5 100644 (file)
@@ -203,80 +203,80 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr)
 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)                                      \
@@ -331,6 +331,13 @@ extern int __put_user_bad(void);
 
 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)
  */
@@ -338,7 +345,6 @@ extern int __get_user_bad(void);
 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 @@ __copy_to_user_asm(void* to, const void* from,  long n)
                                 "   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 @@ __copy_from_user_asm(void* to, const void* from,  long n)
                                 "   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 @@ __copy_from_user_asm(void* to, const void* from,  long n)
  */
 
 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 @@ strncpy_from_user(char *dst, const char *src, long count)
                                 "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 @@ strncpy_from_user(char *dst, const char *src, long count)
                                 "   .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 @@ strnlen_user(const char * src, unsigned long n)
  */
 
 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 @@ clear_user(void *to, unsigned long n)
                                 "   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;
 }
 
index 00335f6200d6fdf37fc0c386b0a0ece6a56db167..cdafd45693f96983e97e1b70aad2d1661578c8ca 100644 (file)
@@ -191,7 +191,7 @@ do {                                                         \
         return (type) (res);                                 \
 } while (0)
 
-#define _svc_clobber "cc", "memory"
+#define _svc_clobber "2", "cc", "memory"
 
 #define _syscall0(type,name)                                 \
 type name(void) {                                            \
index 25f6b752eb1c9ece190cf8d6bef1656075a1a6be..0af48f3cc11b5a44a29f89af52ef53b28465b4ed 100644 (file)
@@ -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
index 1b6253190f50f501354e818083f22f7171f79588..e04b54242ead12cd2d6adc99d248d3c583266da1 100644 (file)
@@ -256,6 +256,18 @@ struct unixware_disklabel {
 
 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
index 6d19fc2a9f66bcf8e979b1cfb1354d64e3a9dc0e..353c45632c385bb386191b2b4aac350570e602a2 100644 (file)
@@ -210,7 +210,7 @@ struct input_event {
 #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 @@ struct input_event {
 #define KEY_EDIT               176
 #define KEY_SCROLLUP           177
 #define KEY_SCROLLDOWN         178
-
-#define KEY_UNKNOWN            180
+#define KEY_KPLEFTPAREN                179
+#define KEY_KPRIGHTPAREN       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 @@ struct input_event {
 #define BUS_GAMEPORT           0x14
 #define BUS_PARPORT            0x15
 #define BUS_AMIGA              0x16
+#define BUS_ADB                        0x17
 
 #ifdef __KERNEL__
 
index 66a5c6c0a2f78f54b05223631dcb51f56b2a1123..8bf738ed3d69d10c8c6448ce6b9f69f88b19e64c 100644 (file)
@@ -356,6 +356,7 @@ extern void openpic_maptimer(u_int timer, u_int cpumask);
 /* 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);
index 910dfb38d80ffbefd7e07d41f71f09ab66f75a33..79339f33b48149b6284b2427a8593db3fbbb2a7a 100644 (file)
 #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
index c6732dc8d9678ebe0dbd9d72bb3bc6e7d2aa7e3f..a69ddf96b939a121d486c60825ffe4ea4fcc5bd7 100644 (file)
@@ -107,6 +107,7 @@ enum
        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 @@ enum
 /* CTL_DEV names: */
 enum {
        DEV_CDROM=1,
-       DEV_HWMON=2
+       DEV_HWMON=2,
+       DEV_MAC_HID=3
 };
 
 /* /proc/sys/dev/cdrom */
@@ -446,6 +448,16 @@ enum {
        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__
 
 extern asmlinkage int sys_sysctl(struct __sysctl_args *);
index cc6cd342c49894055c49b5ae1beb1619c1b3a76b..cca8e462c171cb432707e660b38850e10fabe299 100644 (file)
 #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 @@ static void __init do_basic_setup(void)
         * 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
index 12e9104969e7db1b0cfed73b7123feb93df6a70a..c24dccb1d12b43b71752e34f779e88a1a2c644ee 100644 (file)
@@ -58,6 +58,13 @@ extern int shmall_max;
 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 @@ static ctl_table kern_table[] = {
 #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 --git a/scripts/Lindent b/scripts/Lindent
new file mode 100644 (file)
index 0000000..4f72241
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+indent -kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di0 -nbc -lp -psl $@