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

diff -urN linux-2.2.17-pre2/Makefile linux/Makefile
--- linux-2.2.17-pre2/Makefile	Mon Dec  3 22:05:41 2001
+++ linux/Makefile	Mon Dec  3 22:05:46 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre2
+EXTRAVERSION = pre3
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.17-pre2/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- linux-2.2.17-pre2/arch/ppc/boot/Makefile	Tue Jan  4 10:12:11 2000
+++ linux/arch/ppc/boot/Makefile	Mon Dec  3 22:05:46 2001
@@ -53,6 +53,9 @@
 
 OBJECTS := head.o misc.o ../coffboot/zlib.o
 CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
+ifeq ($(CONFIG_SMP),y)
+CFLAGS += -D__SMP__
+endif
 OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJCOPY_ARGS = -O elf32-powerpc
 
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- linux-2.2.17-pre2/arch/ppc/coffboot/Makefile	Fri Jun  4 13:30:47 1999
+++ linux/arch/ppc/coffboot/Makefile	Mon Dec  3 22:05:46 2001
@@ -3,32 +3,32 @@
 #
 # Paul Mackerras	January 1997
 
-HOSTCC	= gcc
 HOSTCFLAGS = -O -I$(TOPDIR)/include
 
 CC	= $(CROSS_COMPILE)gcc
 LD	= $(CROSS_COMPILE)ld
-CFLAGS	= -O -fno-builtin -I$(TOPDIR)/include
+CFLAGS	= $(CPPFLAGS) -O -fno-builtin
 OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
-	--add-section=image=vmlinux.gz
-LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+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
 GZ = gzip -9
 
-OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
+CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o
 LIBS = $(TOPDIR)/lib/lib.a
 
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build pmac stuff
-CONFIG_PMAC = y
-endif
-
 ifeq ($(CONFIG_PPC64),y)
 MSIZE=.64
 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
@@ -39,39 +39,81 @@
 hack-coff: hack-coff.c
 	$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
 
+znetboot: vmlinux.coff zImage vmlinux.elf
+	cp vmlinux.coff $(TFTPIMAGE)
+	cp vmlinux.elf $(TFTPIMAGE).elf
+
+znetboot.initrd: vmlinux.coff.initrd
+	cp vmlinux.coff.initrd $(TFTPIMAGE)
+	cp vmlinux.elf.initrd $(TFTPIMAGE).elf
+
 floppy: zImage
 #	mount -t hfs /dev/fd0 /mnt
 #	cp vmlinux.coff /mnt
 #	umount /mnt
 
-znetboot: vmlinux.coff
-	cp vmlinux.coff $(TFTPIMAGE)
+coffboot: $(COFFOBJS) no_initrd.o ld.script
+	$(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS)
 
-znetboot.initrd: vmlinux.coff.initrd
-	cp vmlinux.coff.initrd $(TFTPIMAGE)
+coffboot.initrd: $(COFFOBJS) initrd.o ld.script
+	$(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) initrd.o $(LIBS)
+
+piggyback: piggyback.c
+	$(HOSTCC) $(HOSTCFLAGS) -DKERNELBASE=$(KERNELBASE) -o piggyback piggyback.c
 
-coffboot: $(OBJS) ld.script
-	$(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+mknote: mknote.c
+	$(HOSTCC) $(HOSTCFLAGS) -o mknote mknote.c
 
-zImage: vmlinux.coff
+image.o: piggyback vmlinux.gz
+	./piggyback image < vmlinux.gz | $(AS) -o image.o
 
-zImage.initrd: vmlinux.coff.initrd
+initrd.o: ramdisk.image.gz piggyback
+	./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o
 
-vmlinux.coff: coffboot hack-coff vmlinux.gz
+vmlinux.coff: coffboot hack-coff
 	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
 	./hack-coff $@
 	ln -sf vmlinux.coff zImage
 
-vmlinux.coff.initrd: coffboot hack-coff vmlinux.gz ramdisk.image.gz
-	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
-		coffboot $@
+vmlinux.coff.initrd: coffboot.initrd hack-coff
+	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
 	./hack-coff $@
 
+vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote
+	$(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS)
+	./mknote > note
+	$(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote
+	$(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS)
+	./mknote > note
+	$(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
+
+micoffboot: dummy.o
+	$(LD) -o $@ $(COFF_LD_ARGS) dummy.o $(LIBS)
+
+miboot.image: micoffboot hack-coff
+	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz micoffboot $@
+	./hack-coff $@
+
+miboot.image.initrd: micoffboot hack-coff
+	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+	--add-section=initrd=ramdisk.image.gz micoffboot $@
+	./hack-coff $@
+
+zImage: vmlinux.coff vmlinux.elf miboot.image
+
+zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd miboot.image.initrd
+
 else
 znetboot: vmlinux.gz
 
 znetboot.initrd: vmlinux.gz
 
+miboot.image: vmlinux.gz
+
+miboot.image.initrd: vmlinux.gz
+
 coffboot: vmlinux.gz
 
 zImage: vmlinux.gz
@@ -92,5 +134,6 @@
 
 clean:
 	rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz
+	rm -f mknote piggyback vmlinux.elf note
 
 fastdep:
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c
--- linux-2.2.17-pre2/arch/ppc/coffboot/chrpmain.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/chrpmain.c	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+void stop_imac_ethernet(void);
+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 PROG_START	0x00010000
+
+char *avail_ram;
+char *end_avail;
+
+extern char _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+    int ns, oh, i;
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+    extern char _start;
+    
+    printf("chrpboot starting: loaded at 0x%x\n", &_start);
+    if (initrd_len) {
+	initrd_size = initrd_len;
+	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+	a1 = initrd_start;
+	a2 = initrd_size;
+	claim(initrd_start, RAM_END - initrd_start, 0);
+	printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+	       initrd_start, initrd_data, initrd_size);
+	memcpy((char *)initrd_start, initrd_data, initrd_size);
+    }
+    im = image_data;
+    len = image_len;
+    /* claim 3MB starting at PROG_START */
+    claim(PROG_START, 3 << 20, 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);
+	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	gunzip(dst, 3 << 20, im, &len);
+	printf("done %u bytes\n", len);
+    } else {
+	memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    stop_imac_ethernet();
+    stop_imac_usb();
+
+    sa = (unsigned long)PROG_START;
+    printf("start address = 0x%x\n", sa);
+
+    (*(void (*)())sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
+
+#define eieio()	asm volatile("eieio");
+
+void stop_imac_ethernet(void)
+{
+    void *macio, *enet;
+    unsigned int macio_addr[5], enet_reg[6];
+    int len;
+    volatile unsigned int *dbdma;
+
+    macio = finddevice("/pci/mac-io");
+    enet = finddevice("/pci/mac-io/ethernet");
+    if (macio == NULL || enet == NULL)
+	return;
+    len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr));
+    if (len != sizeof(macio_addr))
+	return;
+    len = getprop(enet, "reg", enet_reg, sizeof(enet_reg));
+    if (len != sizeof(enet_reg))
+	return;
+    printf("macio base %x, dma at %x & %x\n",
+	   macio_addr[2], enet_reg[2], enet_reg[4]);
+
+    /* hope this is mapped... */
+    dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]);
+    *dbdma = 0x80;	/* clear the RUN bit */
+    eieio();
+    dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]);
+    *dbdma = 0x80;	/* clear the RUN bit */
+    eieio();
+}
+
+void stop_imac_usb(void)
+{
+    void *usb;
+    unsigned int usb_addr[5];
+    int len;
+    volatile unsigned int *usb_ctrl;
+
+    usb = finddevice("/pci/usb");
+    if (usb == NULL)
+	return;
+    len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr));
+    if (len != sizeof(usb_addr))
+	return;
+    printf("usb base %x\n", usb_addr[2]);
+
+    usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8);
+    *usb_ctrl = 0x01000000;	/* cpu_to_le32(1) */
+    eieio();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p = avail_ram;
+
+    size *= items;
+    size = (size + 7) & -8;
+    avail_ram += size;
+    if (avail_ram > end_avail) {
+	printf("oops... out of memory\n");
+	pause();
+    }
+    return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+	printf("bad gzipped data\n");
+	exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+	i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & COMMENT) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & HEAD_CRC) != 0)
+	i += 2;
+    if (i >= *lenp) {
+	printf("gunzip: ran out of data in header\n");
+	exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+	printf("inflateInit2 returned %d\n", r);
+	exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+	printf("inflate returned %d msg: %s\n", r, s.msg);
+	exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/coffcrt0.S linux/arch/ppc/coffboot/coffcrt0.S
--- linux-2.2.17-pre2/arch/ppc/coffboot/coffcrt0.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/coffcrt0.S	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+	.text
+	.globl	_start
+_start:
+	.long	__start,0,0
+
+	.globl	__start
+__start:
+	lis	9,_start@h
+	lis	8,_etext@ha
+	addi	8,8,_etext@l
+1:	dcbf	0,9
+	icbi	0,9
+	addi	9,9,0x20
+	cmplwi	0,9,8
+	blt	1b
+	b	start
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/coffmain.c linux/arch/ppc/coffboot/coffmain.c
--- linux-2.2.17-pre2/arch/ppc/coffboot/coffmain.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/coffmain.c	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+extern char *claim(unsigned, unsigned, unsigned);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x)	(*(unsigned short *)(x))
+#define get_32be(x)	(*(unsigned *)(x))
+
+#define RAM_START	0xc0000000
+#define PROG_START	RAM_START
+#define RAM_END		(RAM_START + 0x800000)	/* only 8M mapped with BATs */
+
+char *avail_ram;
+char *end_avail;
+
+extern char _start[], _end[];
+extern char image_data[];
+extern int image_len;
+extern char initrd_data[];
+extern int initrd_len;
+
+
+boot(int a1, int a2, void *prom)
+{
+    int ns, oh, i;
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+    
+    printf("coffboot starting: loaded at 0x%x\n", _start);
+    setup_bats(RAM_START);
+    if (initrd_len) {
+	initrd_size = initrd_len;
+	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+	a1 = initrd_start;
+	a2 = initrd_size;
+	claim(initrd_start - RAM_START, RAM_END - initrd_start, 0);
+	printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+	       initrd_start, initrd_data, initrd_size);
+	memcpy((char *)initrd_start, initrd_data, initrd_size);
+    }
+    im = image_data;
+    len = image_len;
+    /* claim 3MB starting at 0 */
+    claim(0, 3 << 20, 0);
+    dst = (void *) RAM_START;
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+	/* claim 512kB for scratch space */
+	avail_ram = claim(0, 512 << 10, 0x10) + RAM_START;
+	end_avail = avail_ram + (512 << 10);
+	printf("avail_ram = %x\n", avail_ram);
+	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	gunzip(dst, 3 << 20, im, &len);
+	printf("done %u bytes\n", len);
+    } else {
+	memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    
+    sa = (unsigned long)PROG_START;
+    printf("start address = 0x%x\n", sa);
+
+#if 0
+    pause();
+#endif
+    (*(void (*)())sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p = avail_ram;
+
+    size *= items;
+    size = (size + 7) & -8;
+    avail_ram += size;
+    if (avail_ram > end_avail) {
+	printf("oops... out of memory\n");
+	pause();
+    }
+    return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+	printf("bad gzipped data\n");
+	exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+	i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & COMMENT) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & HEAD_CRC) != 0)
+	i += 2;
+    if (i >= *lenp) {
+	printf("gunzip: ran out of data in header\n");
+	exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+	printf("inflateInit2 returned %d\n", r);
+	exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+	printf("inflate returned %d msg: %s\n", r, s.msg);
+	exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/crt0.S linux/arch/ppc/coffboot/crt0.S
--- linux-2.2.17-pre2/arch/ppc/coffboot/crt0.S	Sat Aug 16 09:51:08 1997
+++ linux/arch/ppc/coffboot/crt0.S	Mon Dec  3 22:05:46 2001
@@ -9,10 +9,6 @@
 	.text
 	.globl	_start
 _start:
-	.long	__start,0,0
-
-	.globl	__start
-__start:
 	lis	9,_start@h
 	lis	8,_etext@ha
 	addi	8,8,_etext@l
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/misc.S linux/arch/ppc/coffboot/misc.S
--- linux-2.2.17-pre2/arch/ppc/coffboot/misc.S	Wed Sep 30 10:14:16 1998
+++ linux/arch/ppc/coffboot/misc.S	Mon Dec  3 22:05:46 2001
@@ -14,23 +14,26 @@
  */
 	.globl	setup_bats
 setup_bats:
-	mr	4,3
-	mfpvr	3
-	rlwinm	3,3,16,16,31		/* r3 = 1 for 601, 4 for 604 */
-	cmpi	0,3,1
+	mfpvr	5
+	rlwinm	5,5,16,16,31		/* r3 = 1 for 601, 4 for 604 */
+	cmpi	0,5,1
+	li	0,0
 	bne	4f
-	ori	4,4,4			/* set up BAT registers for 601 */
-	li	5,0x7f
-	mtibatu	3,4
-	mtibatl	3,5
-	isync
-	blr
-4:	ori	4,4,0xfe		/* set up BAT registers for 604 */
-	li	5,2
-	mtdbatl	3,5
-	mtdbatu	3,4
-	mtibatl	3,5
-	mtibatu	3,4
+	mtibatl	3,0			/* invalidate BAT first */
+	ori	3,3,4			/* set up BAT registers for 601 */
+	li	4,0x7f
+	mtibatu	3,3
+	mtibatl	3,4
+	b	5f
+4:	mtdbatu	3,0			/* invalidate BATs first */
+	mtibatu	3,0
+	ori	3,3,0xff		/* set up BAT registers for 604 */
+	li	4,2
+	mtdbatl	3,4
+	mtdbatu	3,3
+	mtibatl	3,4
+	mtibatu	3,3
+5:	sync
 	isync
 	blr
 
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/mknote.c linux/arch/ppc/coffboot/mknote.c
--- linux-2.2.17-pre2/arch/ppc/coffboot/mknote.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/mknote.c	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Cort Dougan 1999.
+ *
+ * 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.
+ *
+ * Generate a note section as per the CHRP specification.
+ *
+ */
+
+#include <stdio.h>
+
+#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
+
+int main(void)
+{
+/* header */
+	/* namesz */
+	PL(strlen("PowerPC")+1);
+	/* descrsz */
+	PL(6*4);
+	/* type */
+	PL(0x1275);
+	/* name */
+	printf("PowerPC"); printf("%c", 0);
+	
+/* descriptor */
+	/* real-mode */
+	PL(0xffffffff);
+	/* real-base */
+	PL(0x00c00000);
+	/* real-size */
+	PL(0xffffffff);
+	/* virt-base */
+	PL(0xffffffff);
+	/* virt-size */
+	PL(0xffffffff);
+	/* load-base */
+	PL(0x4000);
+	return 0;
+}
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/no_initrd.c linux/arch/ppc/coffboot/no_initrd.c
--- linux-2.2.17-pre2/arch/ppc/coffboot/no_initrd.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/no_initrd.c	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,2 @@
+char initrd_data[1];
+int initrd_len = 0;
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/piggyback.c linux/arch/ppc/coffboot/piggyback.c
--- linux-2.2.17-pre2/arch/ppc/coffboot/piggyback.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/piggyback.c	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,65 @@
+#include <stdio.h>
+
+extern long ce_exec_config[];
+
+main(int argc, char *argv[])
+{
+	int i, cnt, pos, len;
+	unsigned int cksum, val;
+	unsigned char *lp;
+	unsigned char buf[8192];
+	if (argc != 2)
+	{
+		fprintf(stderr, "usage: %s name <in-file >out-file\n",
+			argv[0]);
+		exit(1);
+	}
+	fprintf(stdout, "#\n");
+	fprintf(stdout, "# Miscellaneous data structures:\n");
+	fprintf(stdout, "# WARNING - this file is automatically generated!\n");
+	fprintf(stdout, "#\n");
+	fprintf(stdout, "\n");
+	fprintf(stdout, "\t.data\n");
+	fprintf(stdout, "\t.globl %s_data\n", argv[1]);
+	fprintf(stdout, "%s_data:\n", argv[1]);
+	pos = 0;
+	cksum = 0;
+	while ((len = read(0, buf, sizeof(buf))) > 0)
+	{
+		cnt = 0;
+		lp = (unsigned char *)buf;
+		len = (len + 3) & ~3;  /* Round up to longwords */
+		for (i = 0;  i < len;  i += 4)
+		{
+			if (cnt == 0)
+			{
+				fprintf(stdout, "\t.long\t");
+			}
+			fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+			val = *(unsigned long *)lp;
+			cksum ^= val;
+			lp += 4;
+			if (++cnt == 4)
+			{
+				cnt = 0;
+				fprintf(stdout, " # %x \n", pos+i-12);
+				fflush(stdout);
+			} else
+			{
+				fprintf(stdout, ",");
+			}
+		}
+		if (cnt)
+		{
+			fprintf(stdout, "0\n");
+		}
+		pos += len;
+	}
+	fprintf(stdout, "\t.globl %s_len\n", argv[1]);
+	fprintf(stdout, "%s_len:\t.long\t0x%x\n", argv[1], pos);
+	fflush(stdout);
+	fclose(stdout);
+	fprintf(stderr, "cksum = %x\n", cksum);
+	exit(0);
+}
+
diff -urN linux-2.2.17-pre2/arch/ppc/coffboot/start.c linux/arch/ppc/coffboot/start.c
--- linux-2.2.17-pre2/arch/ppc/coffboot/start.c	Mon Jan 12 15:18:13 1998
+++ linux/arch/ppc/coffboot/start.c	Mon Dec  3 22:05:46 2001
@@ -33,7 +33,7 @@
     if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
 	exit();
 
-    coffboot(a1, a2, promptr);
+    boot(a1, a2, promptr);
     for (;;)
 	exit();
 }
@@ -62,6 +62,25 @@
     return args.actual;
 }
 
+int writestring(void *f, char *ptr, int nb)
+{
+	int w = 0, i;
+	char *ret = "\r";
+
+	for (i = 0; i < nb; ++i) {
+		if (ptr[i] == '\n') {
+			if (i > w) {
+				write(f, ptr + w, i - w);
+				w = i;
+			}
+			write(f, ret, 1);
+		}
+	}
+	if (w < nb)
+		write(f, ptr + w, nb - w);
+	return nb;
+}
+
 int
 read(void *handle, void *ptr, int nb)
 {
@@ -130,6 +149,29 @@
     return args.phandle;
 }
 
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	unsigned int virt;
+	unsigned int size;
+	unsigned int align;
+	void *ret;
+    } args;
+
+    args.service = "claim";
+    args.nargs = 3;
+    args.nret = 1;
+    args.virt = virt;
+    args.size = size;
+    args.align = align;
+    (*prom)(&args);
+    return args.ret;
+}
+
 int
 getprop(void *phandle, const char *name, void *buf, int buflen)
 {
@@ -161,9 +203,7 @@
 {
     char ch = c;
 
-    if (c == '\n')
-	putc('\r', f);
-    return write(f, &ch, 1) == 1? c: -1;
+    return writestring(f, &ch, 1) == 1? c: -1;
 }
 
 int
@@ -177,7 +217,7 @@
 {
     int n = strlen(str);
 
-    return write(f, str, n) == n? 0: -1;
+    return writestring(f, str, n) == n? 0: -1;
 }
 
 int
@@ -190,7 +230,7 @@
 	case 1:
 	    return ch;
 	case -1:
-	    printk("read(stdin) returned -1\r\n");
+	    printk("read(stdin) returned -1\n");
 	    return -1;
 	}
     }
@@ -264,7 +304,7 @@
 	va_start(args, fmt);
 	n = vsprintf(sprint_buf, fmt, args);
 	va_end(args);
-	write(stdout, sprint_buf, n);
+	writestring(stdout, sprint_buf, n);
 }
 
 int
@@ -276,6 +316,6 @@
 	va_start(args, fmt);
 	n = vsprintf(sprint_buf, fmt, args);
 	va_end(args);
-	write(stdout, sprint_buf, n);
+	writestring(stdout, sprint_buf, n);
 	return n;
 }
diff -urN linux-2.2.17-pre2/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- linux-2.2.17-pre2/arch/ppc/common_defconfig	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/common_defconfig	Mon Dec  3 22:05:46 2001
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -7,15 +7,16 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
-# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -23,7 +24,7 @@
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -34,10 +35,11 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -50,7 +52,6 @@
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -60,8 +61,12 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -70,13 +75,25 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+CONFIG_BLK_DEV_CMD646=y
+# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -84,7 +101,7 @@
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE_PARPORT=m
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -108,10 +125,18 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -133,11 +158,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -155,7 +188,6 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -170,11 +202,12 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -182,7 +215,7 @@
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -220,21 +253,21 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
-# CONFIG_NCR885E is not set
+CONFIG_GMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
@@ -244,7 +277,6 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_SIS900 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
@@ -258,7 +290,12 @@
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
+# CONFIG_PLIP is not set
 CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -276,9 +313,7 @@
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
 # CONFIG_SEALEVEL_4021 is not set
-# CONFIG_COMX is not set
 # CONFIG_DLCI is not set
-# CONFIG_SBNI is not set
 
 #
 # Amateur Radio support
@@ -304,14 +339,12 @@
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-# CONFIG_FB_MATROX_MILLENIUM is not set
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -334,22 +367,13 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -384,10 +408,10 @@
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -453,7 +477,7 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -461,43 +485,13 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=m
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_NM256 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_OSS is not set
 
 #
 # Kernel hacking
diff -urN linux-2.2.17-pre2/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.2.17-pre2/arch/ppc/config.in	Wed Jun  7 14:26:42 2000
+++ linux/arch/ppc/config.in	Mon Dec  3 22:05:46 2001
@@ -8,7 +8,7 @@
 comment 'Platform support'
 define_bool CONFIG_PPC y
 choice 'Processor type' \
-	"6xx/7xx		CONFIG_6xx \
+	"6xx/7xx/7400		CONFIG_6xx \
 	 860/821		CONFIG_8xx" 6xx/7xx
 
 choice 'Machine Type' \
@@ -21,6 +21,11 @@
 	 MBX		CONFIG_MBX" PowerMac
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
+
+if [ "$CONFIG_6xx" = "y" ]; then
+  bool 'Altivec (G4) support' CONFIG_ALTIVEC
+fi
+
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
@@ -77,9 +82,6 @@
 
 bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
-if [ "$CONFIG_FB" = "y" ]; then
-  bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC
-fi
 
 bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK
 bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
@@ -151,6 +153,8 @@
 fi
 
 source net/ax25/Config.in
+
+source net/irda/Config.in
 
 mainmenu_option next_comment
 comment 'ISDN subsystem'
diff -urN linux-2.2.17-pre2/arch/ppc/defconfig linux/arch/ppc/defconfig
--- linux-2.2.17-pre2/arch/ppc/defconfig	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/defconfig	Mon Dec  3 22:05:46 2001
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -7,15 +7,16 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
-# CONFIG_GEMINI is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -23,7 +24,7 @@
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -34,10 +35,11 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
 # CONFIG_BINFMT_JAVA is not set
-# CONFIG_PARPORT is not set
-CONFIG_VGA_CONSOLE=y
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -50,7 +52,6 @@
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -60,8 +61,12 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -70,13 +75,25 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+CONFIG_BLK_DEV_CMD646=y
+# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -84,7 +101,7 @@
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE_PARPORT=m
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -108,10 +125,18 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-CONFIG_SYN_COOKIES=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -133,11 +158,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -155,7 +188,6 @@
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
-# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -170,11 +202,12 @@
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -182,7 +215,7 @@
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -220,21 +253,21 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
-# CONFIG_NCR885E is not set
+CONFIG_GMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
 CONFIG_DE4X5=y
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
@@ -244,7 +277,6 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_SIS900 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_ZNET is not set
@@ -258,7 +290,12 @@
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
+# CONFIG_PLIP is not set
 CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 
@@ -276,9 +313,7 @@
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
 # CONFIG_SEALEVEL_4021 is not set
-# CONFIG_COMX is not set
 # CONFIG_DLCI is not set
-# CONFIG_SBNI is not set
 
 #
 # Amateur Radio support
@@ -304,14 +339,12 @@
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-# CONFIG_FB_MATROX_MILLENIUM is not set
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_MATROX is not set
 CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
@@ -334,22 +367,13 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -384,10 +408,10 @@
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -453,7 +477,7 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -461,43 +485,13 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
-# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-CONFIG_SOUND_CS4232=m
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
-# CONFIG_SOUND_NM256 is not set
-
-#
-# Additional low level sound drivers
-#
-# CONFIG_LOWLEVEL_SOUND is not set
+# CONFIG_SOUND_OSS is not set
 
 #
 # Kernel hacking
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- linux-2.2.17-pre2/arch/ppc/kernel/Makefile	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/Makefile	Mon Dec  3 22:05:46 2001
@@ -7,8 +7,13 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+# Once a gas that groks -mvec is generally available, we'll use it...
 .S.o:
+#ifdef CONFIG_ALTIVEC
+#	$(CC) $(CFLAGS) -D__ASSEMBLY__ -Wa,-mvec -c $< -o $*.o
+#else
 	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
+#endif
 
 O_TARGET := kernel.o
 OX_OBJS := ppc_ksyms.o setup.o
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/checks.c linux/arch/ppc/kernel/checks.c
--- linux-2.2.17-pre2/arch/ppc/kernel/checks.c	Wed Jun  9 14:43:53 1999
+++ linux/arch/ppc/kernel/checks.c	Mon Dec  3 22:05:46 2001
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- linux-2.2.17-pre2/arch/ppc/kernel/chrp_setup.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Dec  3 22:05:46 2001
@@ -488,6 +488,7 @@
 		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;
 #endif		
 	}
 	else
@@ -500,6 +501,7 @@
 		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;
 #endif		
 	}
 #else
@@ -511,6 +513,7 @@
 	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;
 #endif
 #endif
 #endif
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- linux-2.2.17-pre2/arch/ppc/kernel/feature.c	Tue Oct 26 17:53:39 1999
+++ linux/arch/ppc/kernel/feature.c	Mon Dec  3 22:05:46 2001
@@ -8,85 +8,182 @@
  *  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>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <asm/errno.h>
 #include <asm/ohare.h>
+#include <asm/heathrow.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/feature.h>
 
-#define MAX_FEATURE_REGS		2
 #undef DEBUG_FEATURE
 
-static u32 feature_bits_pbook[] = {
-	0,			/* FEATURE_null */
-	OH_SCC_RESET,		/* FEATURE_Serial_reset */
-	OH_SCC_ENABLE,		/* FEATURE_Serial_enable */
-	OH_SCCA_IO,		/* FEATURE_Serial_IO_A */
-	OH_SCCB_IO,		/* FEATURE_Serial_IO_B */
-	OH_FLOPPY_ENABLE,	/* FEATURE_SWIM3_enable */
-	OH_MESH_ENABLE,		/* FEATURE_MESH_enable */
-	OH_IDE_ENABLE,		/* FEATURE_IDE_enable */
-	OH_VIA_ENABLE,		/* FEATURE_VIA_enable */
-	OH_IDECD_POWER,		/* FEATURE_CD_power */
-	OH_BAY_RESET,		/* FEATURE_Mediabay_reset */
-	OH_BAY_ENABLE,		/* FEATURE_Mediabay_enable */
-	OH_BAY_PCI_ENABLE,	/* FEATURE_Mediabay_PCI_enable */
-	OH_BAY_IDE_ENABLE,	/* FEATURE_Mediabay_IDE_enable */
-	OH_BAY_FLOPPY_ENABLE,	/* FEATURE_Mediabay_floppy_enable */
-	0,			/* FEATURE_BMac_reset */
-	0,			/* FEATURE_BMac_IO_enable */
-	0,			/* FEATURE_Modem_Reset -> guess... */
-	OH_IDE_POWER,		/* FEATURE_IDE_DiskPower -> guess... */
-	OH_IDE_RESET		/* FEATURE_IDE_Reset (0 based) -> guess... */
+#define MAX_FEATURE_CONTROLLERS		2
+#define MAX_FEATURE_OFFSET		0x50
+#define FREG(c,r)			(&(((c)->reg)[(r)>>2]))
+
+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
+ */
+static fbit feature_bits_ohare_pbook[] = {
+	{0x38,0,0},			/* FEATURE_null */
+	{0x38,0,OH_SCC_RESET},		/* FEATURE_Serial_reset */
+	{0x38,0,OH_SCC_ENABLE},		/* FEATURE_Serial_enable */
+	{0x38,0,OH_SCCA_IO},		/* FEATURE_Serial_IO_A */
+	{0x38,0,OH_SCCB_IO},		/* FEATURE_Serial_IO_B */
+	{0x38,0,OH_FLOPPY_ENABLE},	/* FEATURE_SWIM3_enable */
+	{0x38,0,OH_MESH_ENABLE},	/* FEATURE_MESH_enable */
+	{0x38,0,OH_IDE0_ENABLE},	/* FEATURE_IDE0_enable */
+	{0x38,1,OH_IDE0_RESET_N},	/* FEATURE_IDE0_reset */
+	{0x38,0,OH_IOBUS_ENABLE},	/* FEATURE_IOBUS_enable */
+	{0x38,1,OH_BAY_RESET_N},	/* FEATURE_Mediabay_reset */
+	{0x38,1,OH_BAY_POWER_N},	/* FEATURE_Mediabay_power */
+	{0x38,0,OH_BAY_PCI_ENABLE},	/* FEATURE_Mediabay_PCI_enable */
+	{0x38,0,OH_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,OH_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
+	{0x38,0,OH_BAY_FLOPPY_ENABLE},	/* FEATURE_Mediabay_floppy_enable */
+	{0x38,0,0},			/* FEATURE_BMac_reset */
+	{0x38,0,0},			/* FEATURE_BMac_IO_enable */
+	{0x38,0,0},			/* 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 */
+	{0x38,0,0},			/* FEATURE_IDE2_reset */
+	{0x38,0,0},			/* FEATURE_Mediabay_IDE_switch */
+	{0x38,0,0},			/* FEATURE_Mediabay_content */
 };
 
-/* assume these are the same as the ohare until proven otherwise */
-static u32 feature_bits_heathrow[] = {
-	0,			/* FEATURE_null */
-	OH_SCC_RESET,		/* FEATURE_Serial_reset */
-	OH_SCC_ENABLE,		/* FEATURE_Serial_enable */
-	OH_SCCA_IO,		/* FEATURE_Serial_IO_A */
-	OH_SCCB_IO,		/* FEATURE_Serial_IO_B */
-	OH_FLOPPY_ENABLE,	/* FEATURE_SWIM3_enable */
-	OH_MESH_ENABLE,		/* FEATURE_MESH_enable */
-	OH_IDE_ENABLE,		/* FEATURE_IDE_enable */
-	OH_VIA_ENABLE,		/* FEATURE_VIA_enable */
-	OH_IDECD_POWER,		/* FEATURE_CD_power */
-	OH_BAY_RESET,		/* FEATURE_Mediabay_reset */
-	OH_BAY_ENABLE,		/* FEATURE_Mediabay_enable */
-	OH_BAY_PCI_ENABLE,	/* FEATURE_Mediabay_PCI_enable */
-	OH_BAY_IDE_ENABLE,	/* FEATURE_Mediabay_IDE_enable */
-	OH_BAY_FLOPPY_ENABLE,	/* FEATURE_Mediabay_floppy_enable */
-	0x80000000,		/* FEATURE_BMac_reset */
-	0x60000000,		/* FEATURE_BMac_IO_enable */
-	0x02000000,		/* FEATURE_Modem_Reset -> guess...*/
-	OH_IDE_POWER,		/* FEATURE_IDE_DiskPower -> guess... */
-	OH_IDE_RESET		/* FEATURE_IDE_Reset (0 based) -> guess... */
+/* Those bits are from a PowerBook. It's possible that desktop machines
+ * based on heathrow need a different definition or some bits removed
+ */
+static fbit feature_bits_heathrow[] = {
+	{0x38,0,0},			/* FEATURE_null */
+	{0x38,0,HRW_RESET_SCC},		/* FEATURE_Serial_reset */
+	{0x38,0,HRW_SCC_ENABLE},	/* FEATURE_Serial_enable */
+	{0x38,0,HRW_SCCA_IO},		/* FEATURE_Serial_IO_A */
+	{0x38,0,HRW_SCCB_IO},		/* 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,HRW_BAY_RESET_N},	/* FEATURE_Mediabay_reset */
+	{0x38,1,HRW_BAY_POWER_N},	/* FEATURE_Mediabay_power */
+	{0x38,0,HRW_BAY_PCI_ENABLE},	/* FEATURE_Mediabay_PCI_enable */
+	{0x38,0,HRW_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,HRW_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
+	{0x38,0,HRW_BAY_FLOPPY_ENABLE},	/* FEATURE_Mediabay_floppy_enable */
+	{0x38,0,HRW_BMAC_RESET},	/* FEATURE_BMac_reset */
+	{0x38,0,HRW_BMAC_IO_ENABLE},	/* FEATURE_BMac_IO_enable */
+	{0x38,1,HRW_MODEM_POWER_N},	/* FEATURE_Modem_power */
+	{0x38,0,HRW_SLOW_SCC_PCLK},	/* FEATURE_Slow_SCC_PCLK */
+	{0x38,1,HRW_SOUND_POWER_N},	/* FEATURE_Sound_Power */
+	{0x38,0,HRW_SOUND_CLK_ENABLE},	/* 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 */
+};
+
+/*
+ * Those bits are from a 1999 G3 PowerBook, with a paddington chip.
+ * Mostly the same as the heathrow.
+ */
+static fbit feature_bits_paddington[] = {
+	{0x38,0,0},			/* FEATURE_null */
+	{0x38,0,0},			/* 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 */
+	{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,HRW_BAY_RESET_N},	/* FEATURE_Mediabay_reset */
+	{0x38,1,HRW_BAY_POWER_N},	/* FEATURE_Mediabay_power */
+	{0x38,0,HRW_BAY_PCI_ENABLE},	/* FEATURE_Mediabay_PCI_enable */
+	{0x38,0,HRW_BAY_IDE_ENABLE},	/* FEATURE_IDE1_enable */
+	{0x38,1,HRW_IDE1_RESET_N},	/* FEATURE_IDE1_reset */
+	{0x38,0,HRW_BAY_FLOPPY_ENABLE},	/* FEATURE_Mediabay_floppy_enable */
+	{0x38,0,HRW_BMAC_RESET},	/* FEATURE_BMac_reset */
+	{0x38,0,HRW_BMAC_IO_ENABLE},	/* FEATURE_BMac_IO_enable */
+	{0x38,1,PADD_MODEM_POWER_N},	/* FEATURE_Modem_power */
+	{0x38,0,HRW_SLOW_SCC_PCLK},	/* FEATURE_Slow_SCC_PCLK */
+	{0x38,1,HRW_SOUND_POWER_N},	/* FEATURE_Sound_Power */
+	{0x38,0,HRW_SOUND_CLK_ENABLE},	/* 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 */
+};
+
+/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
+ */
+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,0},			/* FEATURE_SWIM3_enable */
+	{0x38,0,0},			/* FEATURE_MESH_enable */
+	{0x3c,0,0},			/* FEATURE_IDE0_enable */
+ 	{0x3c,1,0x01000000},		/* 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 */
+	{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 */
+	{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 */
+	{0x34,0,0x00000100},		/* FEATURE_Mediabay_content */
 };
 
 /* definition of a feature controller object */
-struct feature_controller
-{
-	u32*			bits;
+struct feature_controller {
+	fbit*			bits;
 	volatile u32*		reg;
 	struct device_node*	device;
+	spinlock_t		lock;
 };
 
 /* static functions */
 static void
-feature_add_controller(struct device_node *controller_device, u32* bits);
+feature_add_controller(struct device_node *controller_device, fbit* bits);
 
-static int
+static struct feature_controller*
 feature_lookup_controller(struct device_node *device);
 
 /* static varialbles */
-static struct feature_controller	controllers[MAX_FEATURE_REGS];
+static struct feature_controller	controllers[MAX_FEATURE_CONTROLLERS];
 static int				controller_count = 0;
 
 
@@ -96,18 +193,25 @@
 	struct device_node *np;
 
 	np = find_devices("mac-io");
-	while (np != NULL)
-	{
-		feature_add_controller(np, feature_bits_heathrow);
+	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);
+		} else if (device_is_compatible(np, "paddington")) {
+			feature_add_controller(np, feature_bits_paddington);
+		} else {
+			feature_add_controller(np, feature_bits_heathrow);
+		}
 		np = np->next;
 	}
 	if (controller_count == 0)
 	{
 		np = find_devices("ohare");
-		if (np)
-		{
+		if (np) {
 			if (find_devices("via-pmu") != NULL)
-				feature_add_controller(np, feature_bits_pbook);
+				feature_add_controller(np, feature_bits_ohare_pbook);
 			else
 				/* else not sure; maybe this is a Starmax? */
 				feature_add_controller(np, NULL);
@@ -116,17 +220,26 @@
 
 	if (controller_count)
 		printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
+
+#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_DMASOUND_MODULE
+	/* On PowerBooks, we disable the sound chip when dmasound is a module */
+	if (controller_count && find_devices("via-pmu") != NULL) {
+		feature_clear(controllers[0].device, FEATURE_Sound_power);
+		feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
+	}
+#endif	
+#endif
 }
 
 static void
-feature_add_controller(struct device_node *controller_device, u32* bits)
+feature_add_controller(struct device_node *controller_device, fbit* bits)
 {
 	struct feature_controller*	controller;
 	
-	if (controller_count >= MAX_FEATURE_REGS)
-	{
+	if (controller_count >= MAX_FEATURE_CONTROLLERS) {
 		printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
-			controller_device->full_name, MAX_FEATURE_REGS);
+			controller_device->full_name, MAX_FEATURE_CONTROLLERS);
 		return;
 	}
 	controller = &controllers[controller_count];
@@ -140,30 +253,32 @@
 	}
 
 	controller->reg		= (volatile u32 *)ioremap(
-		controller_device->addrs[0].address + OHARE_FEATURE_REG, 4);
+		controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
 
 	if (bits == NULL) {
 		printk(KERN_INFO "Twiddling the magic ohare bits\n");
-		out_le32(controller->reg, STARMAX_FEATURES);
+		out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
 		return;
 	}
 
+	spin_lock_init(&controller->lock);
+	
 	controller_count++;
 }
 
-static int
+static struct feature_controller*
 feature_lookup_controller(struct device_node *device)
 {
 	int	i;
 	
 	if (device == NULL)
-		return -EINVAL;
+		return NULL;
 		
 	while(device)
 	{
 		for (i=0; i<controller_count; i++)
 			if (device == controllers[i].device)
-				return i;
+				return &controllers[i];
 		device = device->parent;
 	}
 
@@ -172,35 +287,38 @@
 		device->name);
 #endif
 	
-	return -ENODEV;
+	return NULL;
 }
 
 int
 feature_set(struct device_node* device, enum system_feature f)
 {
-	int		controller;
-	unsigned long	flags;
+	struct feature_controller*	controller;
+	unsigned long			flags;
+	unsigned long			value;
+	fbit*				bit;
 
 	if (f >= FEATURE_last)
 		return -EINVAL;	
 
 	controller = feature_lookup_controller(device);
-	if (controller < 0)
-		return controller;
+	if (!controller)
+		return -ENODEV;
+	bit = &controller->bits[f];
+	if (!bit->mask)
+		return -EINVAL;
 	
 #ifdef DEBUG_FEATURE
 	printk("feature: <%s> setting feature %d in controller @0x%x\n",
-		device->name, (int)f, (unsigned int)controllers[controller].reg);
+		device->name, (int)f, (unsigned int)controller->reg);
 #endif
 
-	save_flags(flags);
-	cli();
-	out_le32( controllers[controller].reg,
-		 in_le32(controllers[controller].reg) |
-		 controllers[controller].bits[f]);
-	(void)in_le32(controllers[controller].reg);
-	restore_flags(flags);
-	udelay(10);
+	spin_lock_irqsave(&controller->lock, flags);
+	value = in_le32(FREG(controller, bit->reg));
+	value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask);
+	out_le32(FREG(controller, bit->reg), value);
+	(void)in_le32(FREG(controller, bit->reg));
+	spin_unlock_irqrestore(&controller->lock, flags);
 	
 	return 0;
 }
@@ -208,29 +326,32 @@
 int
 feature_clear(struct device_node* device, enum system_feature f)
 {
-	int		controller;
-	unsigned long	flags;
+	struct feature_controller*	controller;
+	unsigned long			flags;
+	unsigned long			value;
+	fbit*				bit;
 
 	if (f >= FEATURE_last)
 		return -EINVAL;	
 
 	controller = feature_lookup_controller(device);
-	if (controller < 0)
-		return controller;
+	if (!controller)
+		return -ENODEV;
+	bit = &controller->bits[f];
+	if (!bit->mask)
+		return -EINVAL;
 	
 #ifdef DEBUG_FEATURE
 	printk("feature: <%s> clearing feature %d in controller @0x%x\n",
-		device->name, (int)f, (unsigned int)controllers[controller].reg);
+		device->name, (int)f, (unsigned int)controller->reg);
 #endif
 
-	save_flags(flags);
-	cli();
-	out_le32( controllers[controller].reg,
-		 in_le32(controllers[controller].reg) &
-		 ~(controllers[controller].bits[f]));
-	(void)in_le32(controllers[controller].reg);
-	restore_flags(flags);
-	udelay(10);
+	spin_lock_irqsave(&controller->lock, flags);
+	value = in_le32(FREG(controller, bit->reg));
+	value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask);
+	out_le32(FREG(controller, bit->reg), value);
+	(void)in_le32(FREG(controller, bit->reg));
+	spin_unlock_irqrestore(&controller->lock, flags);
 	
 	return 0;
 }
@@ -238,16 +359,29 @@
 int
 feature_test(struct device_node* device, enum system_feature f)
 {
-	int		controller;
+	struct feature_controller*	controller;
+	unsigned long			value;
+	fbit*				bit;
 
 	if (f >= FEATURE_last)
 		return -EINVAL;	
 
 	controller = feature_lookup_controller(device);
-	if (controller < 0)
-		return controller;
+	if (!controller)
+		return -ENODEV;
+	bit = &controller->bits[f];
+	if (!bit->mask)
+		return -EINVAL;
 	
-	return (in_le32(controllers[controller].reg) &
-		controllers[controller].bits[f]) != 0;
+#ifdef DEBUG_FEATURE
+	printk("feature: <%s> clearing feature %d in controller @0x%x\n",
+		device->name, (int)f, (unsigned int)controller->reg);
+#endif
+	/* If one feature contains several bits, all of them must be set
+	 * for value to be true, or all of them must be 0 if polarity is
+	 * inverse
+	 */
+	value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
+	return bit->polarity ? (value == 0) : (value == bit->mask);
 }
 
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- linux-2.2.17-pre2/arch/ppc/kernel/head.S	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/head.S	Mon Dec  3 22:05:46 2001
@@ -13,6 +13,7 @@
  *    Copyright (C) 1996 Paul Mackerras.
  *  MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
  *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *  AltiVec additions by Kumar Gala (kumar.gala@motorola.com).
  *
  *  This file contains the low-level support and setup for the
  *  PowerPC platform, including trap and interrupt dispatch.
@@ -82,6 +83,28 @@
 #define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
 
+/*
+ * Once a version of gas that understands the AltiVec instructions
+ * is freely available, we can do this the normal way...  - paulus
+ */
+#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
+#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
+#define MFVSCR(r)	.long	(4<<26)+((r)<<11)+(770<<1)
+#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
+
+#define SAVE_VR(n,b,base)	li b,TSS_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
+#define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
+#define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
+#define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
+#define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
+#define REST_VR(n,b,base)	li b,TSS_VR0+(16*(n)); LVX(n,b,base)
+#define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
+#define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
+#define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
+#define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
+#define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
+
 #define SYNC \
 	sync; \
 	isync
@@ -651,7 +674,26 @@
 	STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
 
 	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+
+#ifndef CONFIG_ALTIVEC
 	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+#else
+/*
+ * The Altivec unavailable trap is at 0x0f20.  Foo.
+ * We effectively remap it to 0x3000.
+ */
+	. = 0xf00
+	b	Trap_0f
+trap_0f_cont:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler
+	.long	UnknownException
+	.long	int_return
+
+	. = 0xf20
+	b	AltiVecUnavailable
+#endif /* CONFIG_ALTIVEC */
 
 #ifndef CONFIG_8xx
 /*
@@ -1169,9 +1211,24 @@
 	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
 
 	. = 0x3000
-#else
+#ifdef CONFIG_ALTIVEC
+AltiVecUnavailable:
+	EXCEPTION_PROLOG
+	bne	load_up_altivec		/* if from user, just load it up */
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler	/* if from kernel, take a trap */
+	.long	KernelAltiVec
+	.long	int_return
+
+/* here are the bits of trap 0xf00 which got displaced */
+Trap_0f:
+	EXCEPTION_PROLOG
+	b	trap_0f_cont
+#endif /* CONFIG_ALTIVEC */
+
+#else /* CONFIG_8xx */
 	. = 0x2000
-#endif
+#endif /* CONFIG_8xx */
 
 /*
  * This code finishes saving the registers to the exception frame
@@ -1493,6 +1550,7 @@
 	REST_GPR(20, r21)
 	REST_2GPRS(22, r21)
 	lwz	r21,GPR21(r21)
+	sync
 	rfi
 	
 #ifdef __SMP__
@@ -1632,6 +1690,135 @@
 #endif /* __SMP__ */
 	blr
 
+#ifdef CONFIG_ALTIVEC
+/* Note that the AltiVec support is closely modeled after the FP
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_altivec:
+/*
+ * Disable AltiVec for the task which had AltiVec previously,
+ * and save its AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ * On SMP we know the AltiVec units are free, since we give it up every
+ * switch.  -- Kumar
+ */
+	mfmsr	r5
+	oris	r5,r5,MSR_VEC@h
+	SYNC
+	mtmsr	r5			/* enable use of AltiVec now */
+	SYNC
+/*
+ * For SMP, we don't do lazy AltiVec switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_altivec in switch_to.
+ */
+#ifndef __SMP__
+#ifndef CONFIG_APUS
+	lis	r6,-KERNELBASE@h
+#else
+	lis	r6,CYBERBASEp@h
+	lwz	r6,0(r6)
+#endif
+	addis	r3,r6,last_task_used_altivec@ha
+	lwz	r4,last_task_used_altivec@l(r3)
+	cmpi	0,r4,0
+	beq	1f
+	add	r4,r4,r6
+	addi	r4,r4,TSS	/* want TSS of last_task_used_altivec */
+	SAVE_32VR(0,r20,r4)
+	MFVSCR(vr0)
+	li	r20,TSS_VSCR
+	STVX(vr0,r20,r4)
+	lwz	r5,PT_REGS(r4)
+	add	r5,r5,r6
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r20,MSR_VEC@h
+	andc	r4,r4,r20	/* disable altivec for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* __SMP__ */
+	/* enable use of AltiVec after return */
+	oris	r23,r23,MSR_VEC@h
+	mfspr	r5,SPRG3		/* current task's TSS (phys) */
+	li	r20,TSS_VSCR
+	LVX(vr0,r20,r5)
+	MTVSCR(vr0)
+	REST_32VR(0,r20,r5)
+#ifndef __SMP__
+	subi	r4,r5,TSS
+	sub	r4,r4,r6
+	stw	r4,last_task_used_altivec@l(r3)
+#endif /* __SMP__ */
+	/* restore registers and return */
+	lwz	r3,_CCR(r21)
+	lwz	r4,_LINK(r21)
+	mtcrf	0xff,r3
+	mtlr	r4
+	REST_GPR(1, r21)
+	REST_4GPRS(3, r21)
+	/* we haven't used ctr or xer */
+	mtspr	SRR1,r23
+	mtspr	SRR0,r22
+	REST_GPR(20, r21)
+	REST_2GPRS(22, r21)
+	lwz	r21,GPR21(r21)
+	SYNC
+	rfi
+
+/*
+ * AltiVec unavailable trap from kernel - print a message, but let
+ * the task use AltiVec in the kernel until it returns to user mode.
+ */
+KernelAltiVec:
+	lwz	r3,_MSR(r1)
+	oris	r3,r3,MSR_VEC@h
+	stw	r3,_MSR(r1)	/* enable use of AltiVec after return */
+	lis	r3,87f@h
+	ori	r3,r3,87f@l
+	mr	r4,r2		/* current */
+	lwz	r5,_NIP(r1)
+	bl	printk
+	b	int_return
+87:	.string	"AltiVec used in kernel  (task=%p, pc=%x)  \n"
+	.align	4
+
+/*
+ * giveup_altivec(tsk)
+ * Disable AltiVec for the task given as the argument,
+ * and save the AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ */
+
+	.globl	giveup_altivec
+giveup_altivec:
+	mfmsr	r5
+	oris	r5,r5,MSR_VEC@h
+	SYNC
+	mtmsr	r5			/* enable use of AltiVec now */
+	SYNC
+	cmpi	0,r3,0
+	beqlr-				/* if no previous owner, done */
+	addi	r3,r3,TSS		/* want TSS of task */
+	lwz	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32VR(0, r4, r3)
+	MFVSCR(vr0)
+	li	r4,TSS_VSCR
+	STVX(vr0, r4, r3)
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r3,MSR_VEC@h
+	andc	r4,r4,r3		/* disable AltiVec for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef __SMP__
+	li	r5,0
+	lis	r4,last_task_used_altivec@ha
+	stw	r5,last_task_used_altivec@l(r4)
+#endif /* __SMP__ */
+	blr
+#endif /* CONFIG_ALTIVEC */
+
 #else  /* CONFIG_8xx */
 	.globl	giveup_fpu
 giveup_fpu:
@@ -1660,10 +1847,6 @@
 	addi	r9,r9,0x6f58		/* translate source addr */
 	cmpw	r31,r9			/* (we have to on chrp) */
 	beq	7f
-#if 0 // still needed ? breaks on me if I don't disable this
-	rlwinm	r4,r4,0,8,31		/* translate source address */
-	add	r4,r4,r3		/* to region mapped with BATs */
-#endif	
 7:	addis	r9,r26,klimit@ha	/* fetch klimit */
 	lwz	r25,klimit@l(r9)
 	addis	r25,r25,-KERNELBASE@h
@@ -1790,14 +1973,23 @@
 	cmpi	0,r9,4			/* check for 604 */
 	cmpi	1,r9,9			/* or 604e */
 	cmpi	2,r9,10			/* or mach5 */
+	cmpi	3,r9,8			/* check for 750 (G3) */
+	cmpi	4,r9,12			/* or 7400 (G4) */
 	cror	2,2,6
 	cror	2,2,10
 	bne	4f
 	ori	r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
 	bne	2,5f
 	ori	r11,r11,HID0_BTCD
-5:	mtspr	HID0,r11		/* superscalar exec & br history tbl */
+	b	5f
 4:
+	cror	14,14,18
+	bne	3,6f
+	ori	r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */
+ 	li	r3,0
+ 	mtspr	ICTC,r3
+5:	mtspr	HID0,r11		/* superscalar exec & br history tbl */
+6:
 #endif /* CONFIG_8xx */
 #ifdef __SMP__
 	/* if we're the second cpu stack and r2 are different
@@ -1878,10 +2070,10 @@
 	li	r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
 	mtspr	SRR0,r4
 	mtspr	SRR1,r3
+	SYNC
 	rfi
 /* Load up the kernel context */
 2:
-	SYNC			/* Force all PTE updates to finish */
 	tlbia			/* Clear all TLB entries */
 	sync			/* wait for tlbia/tlbie to finish */
 #ifdef __SMP__
@@ -1938,6 +2130,7 @@
 #endif /* __SMP__ */
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
+	SYNC
 	rfi			/* enable MMU and jump to start_kernel */
 
 /*
@@ -2114,6 +2307,9 @@
 	mflr	r20		/* Return to switch caller */
 	mfmsr	r22
 	li	r0,MSR_FP	/* Disable floating-point */
+#ifdef CONFIG_ALTIVEC
+	oris	r0,r0,MSR_VEC@h
+#endif /* CONFIG_ALTIVEC */
 	andc	r22,r22,r0
 	stw	r20,_NIP(r1)
 	stw	r22,_MSR(r1)
@@ -2427,6 +2623,38 @@
 	blr
 
 /*
+ * Copy a whole page.  We use the dcbz instruction on the destination
+ * to reduce memory traffic (it eliminates the unnecessary reads of
+ * the destination into cache).  This requires that the destination
+ * is cacheable.
+ */
+_GLOBAL(copy_page)
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+	addi	r3,r3,-4
+	addi	r4,r4,-4
+	li	r5,4
+1:	dcbz	r5,r3
+	lwz	r6,4(r4)
+	lwz	r7,8(r4)
+	lwz	r8,12(r4)
+	lwzu	r9,16(r4)
+	stw	r6,4(r3)
+	stw	r7,8(r3)
+	stw	r8,12(r3)
+	stwu	r9,16(r3)
+	lwz	r6,4(r4)
+	lwz	r7,8(r4)
+	lwz	r8,12(r4)
+	lwzu	r9,16(r4)
+	stw	r6,4(r3)
+	stw	r7,8(r3)
+	stw	r8,12(r3)
+	stwu	r9,16(r3)
+	bdnz	1b
+	blr
+
+/*
  * Flush entries from the hash table with VSIDs in the range
  * given.
  */
@@ -2624,6 +2852,7 @@
 	mtspr	SPRG2,r7
 	mtspr	SRR0,r8
 	mtspr	SRR1,r9
+	SYNC
 	rfi
 1:	addis	r9,r1,-KERNELBASE@h
 	lwz	r8,20(r9)	/* get return address */
@@ -2632,6 +2861,7 @@
 	mtspr	SPRG2,r0
 	mtspr	SRR0,r8
 	mtspr	SRR1,r9
+	SYNC
 	rfi			/* return to caller */
 #endif /* CONFIG_8xx */
 
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h
--- linux-2.2.17-pre2/arch/ppc/kernel/local_irq.h	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/local_irq.h	Mon Dec  3 22:05:46 2001
@@ -26,6 +26,7 @@
 struct irqdesc {
 	struct irqaction *action;
 	struct hw_interrupt_type *ctl;
+	int level;
 };
 
 extern struct irqdesc irq_desc[NR_IRQS];
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- linux-2.2.17-pre2/arch/ppc/kernel/mbx_setup.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/mbx_setup.c	Mon Dec  3 22:05:46 2001
@@ -454,6 +454,7 @@
 	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;
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- linux-2.2.17-pre2/arch/ppc/kernel/misc.S	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/misc.S	Mon Dec  3 22:05:46 2001
@@ -480,6 +480,20 @@
 _GLOBAL(_get_PVR)
 	mfspr	r3,PVR
 	blr
+	
+_GLOBAL(_get_HID0)
+	mfspr	r3,HID0
+	blr
+
+_GLOBAL(_get_ICTC)
+	mfspr	r3,ICTC
+	blr
+
+_GLOBAL(_set_ICTC)
+	mtspr	ICTC,r3
+	blr
+
+	
 /*
 	L2CR functions
 	Copyright © 1997-1998 by PowerLogix R & D, Inc.
@@ -546,6 +560,8 @@
 	rlwinm	r4,r4,16,16,31
 	cmplwi	r4,0x0008
 	beq	thisIs750
+	cmplwi	r4,0x000c
+	beq thisIs750
 	li	r3,-1
 	blr
 	
@@ -640,9 +656,11 @@
 	mfspr	r3,PVR
 	rlwinm	r3,r3,16,16,31
 	cmplwi	r3,0x0008
+	beq	1f
+	cmplwi	r3,0x000c
 	li	r3,0
 	bnelr
-	
+1:	
 	/* Return the L2CR contents */
 	mfspr	r3,L2CR
 	blr
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- linux-2.2.17-pre2/arch/ppc/kernel/mk_defs.c	Mon Aug  9 12:04:57 1999
+++ linux/arch/ppc/kernel/mk_defs.c	Mon Dec  3 22:05:46 2001
@@ -8,7 +8,7 @@
  * #defines from the assembly-language output.
  */
 
-#include <stddef.h>
+#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -48,6 +48,12 @@
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+#ifdef CONFIG_ALTIVEC
+	DEFINE(TSS_VR0, offsetof(struct thread_struct, vr[0]));
+	DEFINE(TSS_VRSAVE, offsetof(struct thread_struct, vrsave));
+	DEFINE(TSS_VSCR, offsetof(struct thread_struct, vscr));
+#endif /* CONFIG_ALTIVEC */
+
 	/* Interrupt register frame */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c
--- linux-2.2.17-pre2/arch/ppc/kernel/openpic.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/openpic.c	Mon Dec  3 22:05:46 2001
@@ -5,6 +5,12 @@
  *
  *  Fixed up IPI and restructured a bit
  *    Cort Dougan <cort@ppc.kernel.org>
+ *
+ *  Added initialisation code for Apple Core99 machines, tweaked a few things
+ *  to avoid bogus interrupts and to make sure the disable function exits with
+ *  the interrupt actually masked.
+ *    Benjamin Herrenschmidt <bh40@calva.net>
+ *  Todo: map interrupts to all available CPUs after the ack round
  * 
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive
@@ -21,10 +27,17 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include "open_pic.h"
+#ifdef __powerpc__
+#include <asm/prom.h>
+#endif
 
 #define REGISTER_DEBUG
 #undef REGISTER_DEBUG
 
+#ifdef __powerpc__
+extern int use_of_interrupt_tree;
+#endif
+
 volatile struct OpenPIC *OpenPIC = NULL;
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
@@ -80,7 +93,7 @@
  *  I/O functions
  */
 #ifdef __i386__
-static inline u_int ld_le32(volatile u_int *addr)
+static inline u_int in_le32(volatile u_int *addr)
 {
 	return *addr;
 }
@@ -95,7 +108,7 @@
 {
 	u_int val;
 
-	val = ld_le32(addr);
+	val = in_le32(addr);
 #ifdef REGISTER_DEBUG
 	printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
 #endif
@@ -142,6 +155,9 @@
 {
 	openpic_setfield(addr, OPENPIC_MASK);
 	/* wait until it's not in use */
+	/* BenH: Is this code really enough ? I would rather check the result
+	 *       and eventually retry ...
+	 */
 	while (openpic_read(addr) & OPENPIC_ACTIVITY);
 	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
 }
@@ -149,6 +165,16 @@
 /*
  *  Initialize the OpenPIC
  */
+
+/* PoweMac note:
+ *
+ * With BootX, we consider the controller as beeing already initialized by MacOS
+ * and we only mask out interrupts.
+ * With OF booting, we initialize the interrupts that we find in the device tree,
+ * other ones are just masked out.
+ * Note: We might want to adjust priorities too.
+ */
+
 __initfunc(void openpic_init(int main_pic))
 {
 	u_int t, i;
@@ -179,13 +205,16 @@
 		      OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
 	printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
 	       NumProcessors, NumSources, OpenPIC);
-	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
-	printk("OpenPIC timer frequency is ");
-	if (timerfreq)
-		printk("%d Hz\n", timerfreq);
-	else
-		printk("not set\n");
-
+	/* Apple's OpenPIC is an IBM MPIC without the timer. */
+	if (_machine != _MACH_Pmac) {
+		timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+		printk("OpenPIC timer frequency is ");
+		if (timerfreq)
+			printk("%d Hz\n", timerfreq);
+		else
+			printk("not set\n");
+	}
+	
 	if ( main_pic )
 	{
 		/* Initialize timer interrupts */
@@ -198,24 +227,60 @@
 	    
 		/* Initialize IPI interrupts */
 		for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-			openpic_initipi(i, 10, OPENPIC_VEC_IPI+i);
+			openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i);
 		}
 	    
-		/* Initialize external interrupts */
-		for (i = 0; i < NumSources; i++) {
-			/* Enabled, Priority 8 */
-			openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
-					i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
-			/* Processor 0 */
-			openpic_mapirq(i, 1<<0);
+		if (_machine != _MACH_Pmac) {
+			/* Initialize external interrupts */
+			for (i = 0; i < NumSources; i++) {
+			    /* Enabled, Priority 8 */
+			    openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
+				i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
+			    /* Processor 0 */
+			    openpic_mapirq(i, 1<<0);
+			}
+		} else {
+			/* Prevent any interrupt from occuring during initialisation.
+			 * Hum... I beleive this is not necessary, Apple does that in
+			 * Darwin's PowerExpress code.
+			 */
+			openpic_set_priority(0, 0xf);
+
+			/* First disable all interrupts and map them to CPU 0 */
+			for (i = 0; i < NumSources; i++) {
+				openpic_disable_irq(i);
+				openpic_mapirq(i, 1<<0);
+			}
+			
+			/* If we use the device tree, then lookup all interrupts and
+			 * initialize them according to sense infos found in the tree
+			 */
+			if (use_of_interrupt_tree) {
+				struct device_node* np = find_all_nodes();
+			    	while(np) {
+				    int j, pri;
+				    pri = strcmp(np->name, "programmer-switch") ? 2 : 7;
+				    for (j=0;j<np->n_intrs;j++) {
+    				    	openpic_initirq(	np->intrs[j].line,
+    				    				pri,
+    				    				np->intrs[j].line,
+    				    				np->intrs[j].sense,
+    				    				np->intrs[j].sense);
+    				    	irq_desc[np->intrs[j].line].level = np->intrs[j].sense;
+    				    }
+				    np = np->next;
+				}
+			} else {
+				/* Fixme: read level value from controller */
+				printk("openpic: WARNING, openpic running without interrupt tree\n");
+			}
 		}
-	    
+
 		/* Initialize the spurious interrupt */
 		openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
 
 		/* Gemini has no i8259 */
-		if ( _machine != _MACH_gemini )
-		{
+		if (( _machine != _MACH_gemini ) && (_machine != _MACH_Pmac)) {
 			/* SIOint (8259 cascade) is special */
 			openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
 			openpic_mapirq(0, 1<<0);
@@ -225,6 +290,14 @@
 		}
 		openpic_set_priority(0, 0);
 		openpic_disable_8259_pass_through();
+
+		/* We ack pending interrupts to avoid blocking them */
+		if (_machine == _MACH_Pmac) {
+			for (i = 0; i < NumSources; i++) {
+				(void)openpic_irq(0);
+				openpic_eoi(0);
+			}
+		}
 	}
 }
 
@@ -281,6 +354,7 @@
 {
 	check_arg_cpu(cpu);
 	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
 }
 
 
@@ -428,12 +502,22 @@
 {
 	check_arg_irq(irq);
 	openpic_clearfield(&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));
 }
 
 void openpic_disable_irq(u_int irq)
 {
 	check_arg_irq(irq);
 	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));
 }
 
 /*
@@ -452,10 +536,11 @@
 	check_arg_vec(vec);
 	openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
 				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
-				OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+				OPENPIC_POLARITY_MASK | OPENPIC_SENSE_MASK,
 				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
-				(pol ? OPENPIC_SENSE_POLARITY : 0) |
-				(sense ? OPENPIC_SENSE_LEVEL : 0));
+				(pol ? OPENPIC_POLARITY_POSITIVE :
+			    		OPENPIC_POLARITY_NEGATIVE) |
+				(sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
 }
 
 /*
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- linux-2.2.17-pre2/arch/ppc/kernel/pci.c	Wed Aug 25 17:29:46 1999
+++ linux/arch/ppc/kernel/pci.c	Mon Dec  3 22:05:46 2001
@@ -93,7 +93,7 @@
 
 	for (; node != 0;node = node->sibling) {
 		class_code = (unsigned int *) get_property(node, "class-code", 0);
-		if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
+		if(class_code && (*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
 			fix_intr(node->child, dev);
 		reg = (unsigned int *) get_property(node, "reg", 0);
 		if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- linux-2.2.17-pre2/arch/ppc/kernel/pmac_pci.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/pmac_pci.c	Mon Dec  3 22:05:46 2001
@@ -28,6 +28,18 @@
 struct bridge_data **bridges, *bridge_list;
 static int max_bus;
 
+struct uninorth_data {
+	struct device_node*	node;
+	volatile unsigned int*	cfg_addr;
+	volatile unsigned int*	cfg_data;
+};
+
+static struct uninorth_data uninorth_bridges[3];
+static int uninorth_count;
+static int uninorth_default = -1;
+ 
+
+
 static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
 
 /*
@@ -71,6 +83,161 @@
 	return 0;
 }
 
+/* This function only works for bus 0, uni-N uses a different mecanism for
+ * other busses (see below)
+ */
+#define UNI_N_CFA0(devfn, off)	\
+	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+	| (((unsigned long)(off)) & 0xFCUL))
+
+/* This one is for type 1 config accesses */
+#define UNI_N_CFA1(bus, devfn, off)	\
+	((((unsigned long)(bus)) << 16) \
+	|(((unsigned long)(devfn)) << 8) \
+	|(((unsigned long)(off)) & 0xFCUL) \
+	|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;
+	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;
+			}
+		}
+		caddr = UNI_N_CFA0(dev_fn, offset);
+	} else
+		caddr = UNI_N_CFA1(bus, dev_fn, offset);
+
+	if (bridge == -1) {
+		printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+		return 0;
+	}
+		
+	/* Uninorth will return garbage if we don't read back the value ! */
+	out_le32(uninorth_bridges[bridge].cfg_addr, caddr);
+	(void)in_le32(uninorth_bridges[bridge].cfg_addr);
+	/* Yes, offset is & 7, not & 3 ! */
+	return (unsigned int)(uninorth_bridges[bridge].cfg_data) + (offset & 0x07);
+}
+
+__pmac
+int uni_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned char *val)
+{
+	unsigned int addr;
+	
+	*val = 0xff;
+	addr = uni_north_access_data(bus, dev_fn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	*val = in_8((volatile unsigned char*)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned short *val)
+{
+	unsigned int addr;
+	
+	*val = 0xffff;
+	addr = uni_north_access_data(bus, dev_fn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	*val = in_le16((volatile unsigned short*)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned int *val)
+{
+	unsigned int addr;
+	
+	*val = 0xffff;
+	addr = uni_north_access_data(bus, dev_fn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	*val = in_le32((volatile unsigned int*)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned char val)
+{
+	unsigned int addr;
+	
+	addr = uni_north_access_data(bus, dev_fn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_8((volatile unsigned char *)addr, val);
+	(void)in_8((volatile unsigned char *)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned short val)
+{
+	unsigned int addr;
+	
+	addr = uni_north_access_data(bus, dev_fn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_le16((volatile unsigned short *)addr, val);
+	(void)in_le16((volatile unsigned short *)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+__pmac
+int uni_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned int val)
+{
+	unsigned int addr;
+	
+	addr = uni_north_access_data(bus, dev_fn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_le32((volatile unsigned int *)addr, val);
+	(void)in_le32((volatile unsigned int *)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+
 __pmac
 int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 				  unsigned char offset, unsigned char *val)
@@ -360,6 +527,36 @@
 	       bp->io_base);
 }
 
+#define GRACKLE_PICR1_STG		0x00000040
+#define GRACKLE_PICR1_LOOPSNOOP		0x00000010
+
+/* N.B. this is called before bridges is initialized, so we can't
+   use grackle_pcibios_{read,write}_config_dword. */
+static inline void grackle_set_stg(struct bridge_data *bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_STG) :
+		(val & ~GRACKLE_PICR1_STG);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+static inline void grackle_set_loop_snoop(struct bridge_data *bp, int enable)
+{
+	unsigned int val;
+
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	val = in_le32((volatile unsigned int *)bp->cfg_data);
+	val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
+		(val & ~GRACKLE_PICR1_LOOPSNOOP);
+	out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+}
+
+
 __initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end))
 {
 	int bus;
@@ -411,21 +608,49 @@
 			printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
 			       bus_range[1]);
 		printk(" controlled by %s at %x\n", dev->name, addr->address);
+		if (device_is_compatible(dev, "uni-north")) {
+			int i = uninorth_count++;
+			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;
+			/* 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.
+			 * That means that we cannot do io cycles on the AGP bus nor the internal
+			 * ethernet/fw bus. Fortunately, they appear not to be needed on iMac DV
+			 * and G4 neither.
+			 */
+			if (addr->address == 0xf2000000)
+				uninorth_default = i;
+			else
+				continue;
+		}
 		bp = (struct bridge_data *) *mem_ptr;
 		*mem_ptr += sizeof(struct bridge_data);
-		if (strcmp(dev->name, "pci") != 0) {
-			bp->cfg_addr = (volatile unsigned int *)
-				ioremap(addr->address + 0x800000, 0x1000);
-			bp->cfg_data = (volatile unsigned char *)
-				ioremap(addr->address + 0xc00000, 0x1000);
-			bp->io_base = (void *) ioremap(addr->address, 0x10000);
-		} else {
-			/* XXX */
+		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);
+		} else if (strcmp(dev->name, "pci") == 0) {
+			/* XXX assume this is a mpc106 (grackle) */
 			bp->cfg_addr = (volatile unsigned int *)
 				ioremap(0xfec00000, 0x1000);
 			bp->cfg_data = (volatile unsigned char *)
 				ioremap(0xfee00000, 0x1000);
                         bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
+                        if (machine_is_compatible("AAPL,PowerBook1998"))
+                        	grackle_set_loop_snoop(bp, 1);
+#if 0 			/* Disabled for now, HW problems ??? */
+			grackle_set_stg(bp, 1);
+#endif
+		} else {
+			/* a `bandit' or `chaos' bridge */
+			bp->cfg_addr = (volatile unsigned int *)
+				ioremap(addr->address + 0x800000, 0x1000);
+			bp->cfg_data = (volatile unsigned char *)
+				ioremap(addr->address + 0xc00000, 0x1000);
+			bp->io_base = (void *) ioremap(addr->address, 0x10000);
 		}
 		if (isa_io_base == 0)
 			isa_io_base = (unsigned long) bp->io_base;
@@ -468,7 +693,13 @@
 		if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
 		    !pin)
 			continue; /* No interrupt generated -> no fixup */
-                fix_intr(bp->node->child, dev);
+		/* We iterate all instances of uninorth for now */	
+		if (uninorth_count && dev->bus->number == 0) {
+			int i;
+			for (i=0;i<uninorth_count;i++)
+				fix_intr(uninorth_bridges[i].node->child, dev);
+		} else
+                	fix_intr(bp->node->child, dev);
 	}
 }
 
@@ -476,9 +707,17 @@
 void
 pmac_setup_pci_ptrs(void))
 {
-	if (find_devices("pci") != 0) {
-		/* looks like a G3 powermac */
-		set_config_access_method(grackle);
+	struct device_node* np;
+
+	np = find_devices("pci");
+	if (np != 0) {
+		if (device_is_compatible(np, "uni-north")) {
+			/* looks like an Core99 powermac */
+			set_config_access_method(uni);
+		} else {
+			/* looks like a G3 powermac */
+			set_config_access_method(grackle);
+		}
 	} else {
 		set_config_access_method(pmac);
 	}
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- linux-2.2.17-pre2/arch/ppc/kernel/pmac_pic.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/pmac_pic.c	Mon Dec  3 22:05:46 2001
@@ -4,6 +4,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/pci.h>
+#include <linux/openpic.h>
 #include <asm/pci-bridge.h>
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -27,6 +28,7 @@
 
 static int max_irqs;
 static int max_real_irqs;
+static int has_openpic = 0;
 
 #define MAXCOUNT 10000000
 
@@ -104,6 +106,18 @@
         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,
@@ -126,6 +140,17 @@
 	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;
@@ -196,6 +221,29 @@
         }
 #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)
@@ -350,6 +398,36 @@
         struct device_node *irqctrler;
         volatile struct pmac_irq_hw *addr;
 	int second_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.
+	 */
+	irqctrler = find_type_devices("open-pic");
+	if (irqctrler != NULL) {
+	    printk("PowerMac using OpenPIC irq controller\n");
+	    if (irqctrler->n_addrs > 0) {
+#ifdef CONFIG_XMON
+		struct device_node* pswitch;
+#endif /* CONFIG_XMON */	
+		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;
+		    irq_desc[i].level = 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 */
+		return;
+	    }
+	    irqctrler = NULL;
+	}
 
 	/*
 	 * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- linux-2.2.17-pre2/arch/ppc/kernel/pmac_setup.c	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/pmac_setup.c	Mon Dec  3 22:05:46 2001
@@ -87,6 +87,7 @@
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern void pmac_nvram_update(void);
 
 unsigned char drive_info;
 
@@ -95,11 +96,14 @@
 
 extern char saved_command_line[];
 
+extern int pmac_newworld;
+
 #define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
 
 extern void zs_kgdb_hook(int tty_num);
 static void ohare_init(void);
 static void init_p2pbridge(void);
+static void init_uninorth(void);
 
 __pmac
 int
@@ -187,6 +191,10 @@
 			len += sprintf(buffer+len, "l2cr override\t: 0x%x\n", *l2cr);
 		}
 	}
+
+	/* Indicate newworld/oldworld */
+	len += sprintf(buffer+len, "pmac-generation\t: %s\n",
+		pmac_newworld ? "NewWorld" : "OldWorld");		
 	
 	return len;
 }
@@ -246,8 +254,10 @@
 		if (fp != 0) {
 			switch (_get_PVR() >> 16) {
 			case 4:		/* 604 */
+			case 8:		/* G3 */
 			case 9:		/* 604e */
 			case 10:	/* mach V (604ev5) */
+			case 12:	/* G4 */
 			case 20:	/* 620 */
 				loops_per_sec = *fp;
 				break;
@@ -266,9 +276,10 @@
 
 	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
 	init_p2pbridge();
-
+	init_uninorth();
+	
 	/* Checks "l2cr-value" property in the registry */
-	if ( (_get_PVR() >> 16) == 8) {
+	if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
 		struct device_node *np = find_devices("cpus");		
 		if (np == 0)
 			np = find_type_devices("cpu");		
@@ -288,7 +299,6 @@
 		printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
 			ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
 				? "enabled" : "disabled");
-
 	feature_init();
 
 #ifdef CONFIG_KGDB
@@ -355,6 +365,32 @@
 	}
 }
 
+__initfunc(static void init_uninorth(void))
+{
+	/* 
+	 * Turns on the gmac clock so that it responds to PCI cycles
+	 * later, the driver may want to turn it off again to save
+	 * power when interface is down
+	 */
+	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) |= 2;
+		eieio();
+	}
+}
+
 extern char *bootpath;
 extern char *bootdevice;
 void *boot_host;
@@ -402,14 +438,13 @@
 #endif
 
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
-extern int pmac_ide_count;
-extern struct device_node *pmac_ide_node[];
-static int ide_majors[] = { 3, 22, 33, 34, 56, 57 };
+
+extern kdev_t pmac_find_ide_boot(char *bootdevice, int n);
 
 __initfunc(kdev_t find_ide_boot(void))
 {
 	char *p;
-	int i, n;
+	int n;
 
 	if (bootdevice == NULL)
 		return 0;
@@ -418,18 +453,7 @@
 		return 0;
 	n = p - bootdevice;
 
-	/*
-	 * Look through the list of IDE interfaces for this one.
-	 */
-	for (i = 0; i < pmac_ide_count; ++i) {
-		char *name = pmac_ide_node[i]->full_name;
-		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
-			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
-		}
-	}
-
-	return 0;
+	return pmac_find_ide_boot(bootdevice, n);
 }
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
 
@@ -468,7 +492,7 @@
 	if (boot_dev == 0 || dev == boot_dev) {
 		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
 		boot_dev = NODEV;
-		printk(" (root)");
+		printk(" (root on %d)", part);
 	}
 }
 
@@ -477,6 +501,8 @@
 {
 	struct adb_request req;
 
+	pmac_nvram_update();
+	
 	switch (adb_hardware) {
 	case ADB_VIACUDA:
 		cuda_request(&req, NULL, 2, CUDA_PACKET,
@@ -497,6 +523,8 @@
 {
 	struct adb_request req;
 
+	pmac_nvram_update();
+	
 	switch (adb_hardware) {
 	case ADB_VIACUDA:
 		cuda_request(&req, NULL, 2, CUDA_PACKET,
@@ -515,7 +543,6 @@
 void
 pmac_halt(void)
 {
-   pmac_power_off();
 }
 
 
@@ -541,11 +568,15 @@
         return 0;
 }
 
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+extern ide_ioreg_t pmac_ide_get_base(int index);
+#endif
+
 ide_ioreg_t
 pmac_ide_default_io_base(int index)
 {
 #if defined(CONFIG_BLK_DEV_IDE_PMAC)
-        return pmac_ide_regbase[index];
+        return pmac_ide_get_base(index);
 #else
 	return 0;
 #endif
@@ -625,6 +656,7 @@
 	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;
 #endif
 #endif
 
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- linux-2.2.17-pre2/arch/ppc/kernel/pmac_support.c	Sun Nov 15 10:51:43 1998
+++ linux/arch/ppc/kernel/pmac_support.c	Mon Dec  3 22:05:46 2001
@@ -1,10 +1,19 @@
 /*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
+ * Contains support for the nvram.
+ * 
+ *   Copyright (C) 2000 Paul Mackerras
+ *   Copyright (C) 2000 Benjamin Herrenschmidt
+ *
+ * ToDo: Handle type 0 and type 1 "NameRegistry" NVRAM properties. Those
+ *       contain, among other things, the brightness, video mode, etc...
  */
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/reboot.h>
 #include <linux/nvram.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
 #include <asm/init.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
@@ -13,6 +22,10 @@
 #include <asm/prom.h>
 #include <asm/adb.h>
 #include <asm/pmu.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+
+#undef DEBUG
 
 /*
  * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
@@ -20,24 +33,236 @@
 static int nvram_naddrs;
 static volatile unsigned char *nvram_addr;
 static volatile unsigned char *nvram_data;
-static int nvram_mult;
+static int nvram_mult, is_core_99;
+static char* nvram_image;
+static int core99_bank = 0;
+
+extern int pmac_newworld;
+
+#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE	0x5a
+#define CORE99_ADLER_START	0x14
+
+/* Core99 nvram is a flash */
+#define CORE99_FLASH_STATUS_DONE	0x80
+#define CORE99_FLASH_STATUS_ERR		0x38
+#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
+#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
+#define CORE99_FLASH_CMD_RESET		0xff
+#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
+
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8		signature;
+  u8		cksum;
+  u16		len;
+  char          name[12];
+  u8		data[0];
+};
+
+struct core99_header {
+  struct chrp_header	hdr;
+  u32			adler;
+  u32			generation;
+  u32			reserved[2];
+};
+
+static int nvram_partitions[3];
+
+static u8
+chrp_checksum(struct chrp_header* hdr)
+{
+	u8 *ptr;
+	u16 sum = hdr->signature;
+	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+		sum += *ptr;
+	while (sum > 0xFF)
+		sum = (sum & 0xFF) + (sum>>8);
+	return sum;
+}
+
+static u32
+core99_calc_adler(u8 *buffer)
+{
+	int cnt;
+	u32 low, high;
+
+   	buffer += CORE99_ADLER_START;
+	low = 1;
+	high = 0;
+	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+		if ((cnt % 5000) == 0) {
+			high  %= 65521UL;
+			high %= 65521UL;
+		}
+		low += buffer[cnt];
+		high += low;
+	}
+	low  %= 65521UL;
+	high %= 65521UL;
+  
+	return (high << 16) | low;
+}
+
+static u32
+core99_check(u8* datas)
+{
+	struct core99_header* hdr99 = (struct core99_header*)datas;
+
+	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+#ifdef DEBUG
+		printk("Invalid signature\n");
+#endif		
+		return 0;
+	}
+	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+#ifdef DEBUG
+		printk("Invalid checksum\n");
+#endif
+		return 0;
+	}
+	if (hdr99->adler != core99_calc_adler(datas)) {
+#ifdef DEBUG
+		printk("Invalid adler\n");
+#endif
+		return 0;
+	}
+	return hdr99->generation;
+}
+
+static int
+core99_erase_bank(int bank)
+{
+	int stat, i;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
+	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
+	do { stat = in_8(base); }
+	while(!(stat & CORE99_FLASH_STATUS_DONE));
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on erase !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != 0xff) {
+			printk("nvram: flash erase failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
 
-#define NVRAM_SIZE	0x2000	/* 8kB of non-volatile RAM */
+static int
+core99_write_bank(int bank, u8* datas)
+{
+	int i, stat = 0;
+	
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+	
+	for (i=0; i<NVRAM_SIZE; i++) {
+		out_8(base+i, CORE99_FLASH_CMD_WRITE_SETUP);
+		out_8(base+i, datas[i]);
+		do { stat = in_8(base); }
+		while(!(stat & CORE99_FLASH_STATUS_DONE));
+		if (stat & CORE99_FLASH_STATUS_ERR)
+			break;
+	}
+	out_8(base, CORE99_FLASH_CMD_RESET);
+	if (stat & CORE99_FLASH_STATUS_ERR) {
+		printk("nvram: flash error 0x%02x on write !\n", stat);
+		return -ENXIO;
+	}
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != datas[i]) {
+			printk("nvram: flash write failed !\n");
+			return -ENXIO;
+		}
+	return 0;	
+}
 
+static void
+lookup_partitions(void)
+{
+	u8 buffer[17];
+	int i, offset;
+	struct chrp_header* hdr;
+
+	if (pmac_newworld) {
+		nvram_partitions[pmac_nvram_OF] = -1;
+		nvram_partitions[pmac_nvram_XPRAM] = -1;
+		nvram_partitions[pmac_nvram_NR] = -1;
+		hdr = (struct chrp_header *)buffer;
+	
+		offset = 0;
+		do {
+			for (i=0;i<16;i++)
+				buffer[i] = nvram_read_byte(offset+i);
+			if (!strcmp(hdr->name, "common"))
+				nvram_partitions[pmac_nvram_OF] = offset + 0x10;
+			if (!strcmp(hdr->name, "APL,MacOS75")) {
+				nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
+				nvram_partitions[pmac_nvram_NR] = offset + 0x110;
+			}
+			offset += (hdr->len * 0x10);
+		} while(offset < NVRAM_SIZE);
+	} else {
+		nvram_partitions[pmac_nvram_OF] = 0x1800;
+		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
+		nvram_partitions[pmac_nvram_NR] = 0x1400;
+	}	
+#ifdef DEBUG
+	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+#endif	
+}
 
 __init
 void pmac_nvram_init(void)
 {
 	struct device_node *dp;
 
+	nvram_naddrs = 0;
+
 	dp = find_devices("nvram");
 	if (dp == NULL) {
 		printk(KERN_ERR "Can't find NVRAM device\n");
-		nvram_naddrs = 0;
 		return;
 	}
 	nvram_naddrs = dp->n_addrs;
-	if (_machine == _MACH_chrp && nvram_naddrs == 1) {
+	is_core_99 = device_is_compatible(dp, "nvram,flash");
+	printk("pmac nvram is core99: %d\n", is_core_99);
+	if (is_core_99) {
+		int i;
+		u32 gen_bank0, gen_bank1;
+		
+		if (nvram_naddrs < 1) {
+			printk(KERN_ERR "nvram: no address\n");
+			return;
+		}
+		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
+		if (!nvram_image) {
+			printk(KERN_ERR "nvram: can't allocate image\n");
+			return;
+		}
+		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+#ifdef DEBUG
+		printk("nvram: Checking bank 0...\n");
+#endif
+		gen_bank0 = core99_check((u8 *)nvram_data);
+		gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+		core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+#ifdef DEBUG
+		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+		printk("nvram: Active bank is: %d\n", core99_bank);
+#endif
+		for (i=0; i<NVRAM_SIZE; i++)
+			nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
 		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_mult = 1;
 	} else if (nvram_naddrs == 1) {
@@ -52,9 +277,38 @@
 		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
 		       nvram_naddrs);
 	}
+	lookup_partitions();
 }
 
-unsigned char nvram_read_byte(int addr)
+void
+pmac_nvram_update(void)
+{
+	struct core99_header* hdr99;
+	
+	if (!is_core_99 || !nvram_data || !nvram_image)
+		return;
+	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+		NVRAM_SIZE))
+		return;
+#ifdef DEBUG
+	printk("Updating nvram...\n");
+#endif
+	hdr99 = (struct core99_header*)nvram_image;
+	hdr99->generation++;
+	hdr99->hdr.signature = CORE99_SIGNATURE;
+	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+	hdr99->adler = core99_calc_adler(nvram_image);
+	core99_bank = core99_bank ? 0 : 1;
+	if (core99_erase_bank(core99_bank)) {
+		printk("nvram: Error erasing bank %d\n", core99_bank);
+		return;
+	}
+	if (core99_write_bank(core99_bank, nvram_image))
+		printk("nvram: Error writing bank %d\n", core99_bank);
+}
+
+unsigned char
+nvram_read_byte(int addr)
 {
 	struct adb_request req;
 
@@ -67,6 +321,8 @@
 			pmu_poll();
 		return req.reply[1];
 	case 1:
+		if (is_core_99)
+			return nvram_image[addr];
 		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
 	case 2:
 		*nvram_addr = addr >> 5;
@@ -76,7 +332,8 @@
 	return 0;
 }
 
-void nvram_write_byte(unsigned char val, int addr)
+void
+nvram_write_byte(unsigned char val, int addr)
 {
 	struct adb_request req;
 
@@ -89,6 +346,10 @@
 			pmu_poll();
 		break;
 	case 1:
+		if (is_core_99) {
+			nvram_image[addr] = val;
+			break;
+		}
 		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
 		break;
 	case 2:
@@ -99,3 +360,32 @@
 	}
 	eieio();
 }
+
+int
+pmac_get_partition(int partition)
+{
+	return nvram_partitions[partition];
+}
+
+u8
+pmac_xpram_read(int xpaddr)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return 0;
+		
+	return nvram_read_byte(xpaddr + offset);
+}
+
+void
+pmac_xpram_write(int xpaddr, u8 data)
+{
+	int offset = nvram_partitions[pmac_nvram_XPRAM];
+	
+	if (offset < 0)
+		return;
+		
+	nvram_write_byte(xpaddr + offset, data);
+}
+
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c
--- linux-2.2.17-pre2/arch/ppc/kernel/ppc-stub.c	Wed Aug 25 17:29:46 1999
+++ linux/arch/ppc/kernel/ppc-stub.c	Mon Dec  3 22:05:46 2001
@@ -351,7 +351,7 @@
 
 static inline void set_msr(int msr)
 {
-	asm volatile("mfmsr %0" : : "r" (msr));
+	asm volatile("mtmsr %0" : : "r" (msr));
 }
 
 /* Set up exception handlers for tracing and breakpoints
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl
--- linux-2.2.17-pre2/arch/ppc/kernel/ppc_asm.tmpl	Mon Jan 12 15:18:13 1998
+++ linux/arch/ppc/kernel/ppc_asm.tmpl	Mon Dec  3 22:05:46 2001
@@ -64,3 +64,36 @@
 #define	fr29	29
 #define	fr30	30
 #define	fr31	31
+
+#define	vr0	0
+#define	vr1	1
+#define	vr2	2
+#define	vr3	3
+#define	vr4	4
+#define	vr5	5
+#define	vr6	6
+#define	vr7	7
+#define	vr8	8
+#define	vr9	9
+#define	vr10	10
+#define	vr11	11
+#define	vr12	12
+#define	vr13	13
+#define	vr14	14
+#define	vr15	15
+#define	vr16	16
+#define	vr17	17
+#define	vr18	18
+#define	vr19	19
+#define	vr20	20
+#define	vr21	21
+#define	vr22	22
+#define	vr23	23
+#define	vr24	24
+#define	vr25	25
+#define	vr26	26
+#define	vr27	27
+#define	vr28	28
+#define	vr29	29
+#define	vr30	30
+#define	vr31	31
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- linux-2.2.17-pre2/arch/ppc/kernel/ppc_htab.c	Wed Aug 25 17:29:46 1999
+++ linux/arch/ppc/kernel/ppc_htab.c	Mon Dec  3 22:05:46 2001
@@ -547,7 +547,8 @@
 		"0.5", "1.0", "(reserved2)", "(reserved3)"
 	};
 
-	if ( (_get_PVR() >> 16) != 8) return -EFAULT;
+	if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
+		return -EFAULT;
 	
 	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
 		*lenp = 0;
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.2.17-pre2/arch/ppc/kernel/ppc_ksyms.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Mon Dec  3 22:05:46 2001
@@ -46,9 +46,10 @@
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
-asmlinkage long long __ashrdi3(long long, int);
-asmlinkage long long __lshrdi3(long long, int);
-asmlinkage int abs(int);
+long long __ashrdi3(long long, int);
+long long __ashldi3(long long, int);
+long long __lshrdi3(long long, int);
+int abs(int);
 
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
@@ -152,6 +153,7 @@
 
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(init_mm);
 
 EXPORT_SYMBOL(__cli);
 EXPORT_SYMBOL(__sti);
@@ -164,6 +166,11 @@
 EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(xchg_u32);
+
+#ifdef CONFIG_ALTIVEC
+EXPORT_SYMBOL(giveup_altivec);
+#endif
+
 #ifdef __SMP__
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
@@ -200,6 +207,8 @@
 EXPORT_SYMBOL(find_phandle);
 EXPORT_SYMBOL(device_is_compatible);
 EXPORT_SYMBOL(machine_is_compatible);
+EXPORT_SYMBOL(find_pci_device_OFnode);
+EXPORT_SYMBOL(find_all_nodes);
 EXPORT_SYMBOL(get_property);
 EXPORT_SYMBOL(pci_io_base);
 EXPORT_SYMBOL(pci_device_loc);
@@ -210,14 +219,15 @@
 EXPORT_SYMBOL(note_scsi_host);
 #endif
 EXPORT_SYMBOL(kd_mksound);
-#ifdef CONFIG_PMAC
+/*#ifdef CONFIG_PMAC */
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
-#endif /* CONFIG_PMAC */
+/*#endif*/ /* CONFIG_PMAC */
 
 EXPORT_SYMBOL(abs);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
 EXPORT_SYMBOL_NOVERS(__lshrdi3);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- linux-2.2.17-pre2/arch/ppc/kernel/prep_pci.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/prep_pci.c	Mon Dec  3 22:05:46 2001
@@ -8,6 +8,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -36,7 +37,7 @@
 unsigned char *Motherboard_routes;
 void (*Motherboard_non0)(struct pci_dev *);
 
-void Mesquite_Map_Non0(struct pci_dev *);
+void Powerplus_Map_Non0(struct pci_dev *);
 
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
@@ -508,6 +509,51 @@
         13      /* Line 4 */
 };
 
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+	unsigned char primary[4];	/* INT A-D */
+	unsigned char secondary[4];	/* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8.  These values are offset by 
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list =
+{
+	{25, 26, 27, 28},
+	{21, 22, 23, 24}
+};
+
+/* 
+ * For the MCP750 (system slot board), bus 0 PCI INTs A-D are routed
+ * to OpenPIC inputs 8-11.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 12-15.  These values are offset by 16
+ * in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list =
+{
+	{24, 25, 26, 27},
+	{28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */ 
+static unsigned char prep_pci_intpins[4][4] =
+{
+        { 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
+        { 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
+        { 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
+        { 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
+};
+
 /* We have to turn on LEVEL mode for changed IRQ's */
 /* All PCI IRQ's need to be level mode, so this should be something
  * other than hard-coded as well... IRQ's are individually mappable
@@ -685,8 +731,7 @@
 #define MOT_RAVEN_PRESENT	0x1
 #define MOT_HAWK_PRESENT	0x2
 
-/* Keyboard present flag */
-int prep_kbd_present = 1;   /* Keyboard present by default */
+int mot_entry = -1;
 
 int MotMPIC = 0;
 int mot_multi = 0;
@@ -751,13 +796,17 @@
 		mot_multi = 1;
 	}
 
-	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
-	 * no keyboard controller and we have to indicate that.
+	/*
+	 * If a Motorola MVME2300, 2400, or MCPN750 board is detected
+	 * disable keyboard controller initialization to avoid system
+	 * hangs.
 	 */
 	base_mod = inb(MOTOROLA_BASETYPE_REG);
 	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
-	    (base_mod == 0xFA) || (base_mod == 0xE1))
-		prep_kbd_present = 0;
+	    (base_mod == 0xFA) || (base_mod == 0xE1)) {
+		ppc_md.kbd_leds	= NULL; 
+		ppc_md.kbd_init_hw = NULL; 
+	}
 
 	return 1;
 }
@@ -771,33 +820,35 @@
 	unsigned char	*map;
 	unsigned char	*routes;
 	void		(*map_non0_bus)(struct pci_dev *);	/* For boards with more than bus 0 devices. */
+	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+	unsigned char	secondary_bridge_devfn;	/* devfn of secondary bus transparent bridge */
 } mot_info[] = {
-	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, NULL},
-	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes,	NULL},
-	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL},
-	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes,	NULL},
-	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes,	NULL},
-	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Mesquite_Map_Non0},
-	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL},
-	{0x000, 0x00, 0x00, "",					NULL,			NULL,	NULL}
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0x00},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes,	NULL, NULL, 0x00},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL,	NULL, 0x00}
 };
 
 __initfunc(unsigned long prep_route_pci_interrupts(void))
@@ -812,7 +863,6 @@
 		unsigned char  cpu_type;
 		unsigned char  base_mod;
 		int	       entry;
-		int	       mot_entry = -1;
 
 		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
 		base_mod = inb(MOTOROLA_BASETYPE_REG);
@@ -989,91 +1039,91 @@
 	return 0;
 }
 
-static unsigned int pci_localpirqs[4] =
-{
-	24,
-	25,
-	26,
-	27
-};
-
-static unsigned int pci_remotepirqs[4] =
-{
-	28,
-	29,
-	30,
-	31
-};
-
-static unsigned int pci_remotedev = 0xc0;
-
+/*
+ * Remove a device from the kernel PCI device list based on its 
+ * devfn identifier.
+ */
+__initfunc(
 void
-Mesquite_Map_Non0(struct pci_dev *pdev)
+prep_exclude_pci_device(unsigned char devfn)
+)
 {
-	struct pci_bus  *pbus;          /* Parent Bus Structure Pointer */
-	unsigned int    devnum;         /* Accumulated Device Number */
-	unsigned int    irq;            /* IRQ Value */
-
-	/*
-	**    Device Interrupt Line register initialization.
-	**    The IRQ line number will be generated after
-	**    taking into account all the PCI-2-PCI bridge
-	**    devices between the device and the Host Bridge.
-	*/
-	devnum = PCI_SLOT(pdev->devfn);
-	pbus = pdev->bus;
+	struct pci_dev *dev, *pdev = NULL;
 
-	while ((pbus->parent)->primary != (pbus->parent)->secondary)
-	{
-	    devnum += PCI_SLOT((pbus->self)->devfn);
+	/* Walk the pci device list */
+	for(dev=pci_devices; dev; dev=dev->next) {
+		if (dev->devfn == devfn)
+		{
+			/*
+			 * If we find a matching device, adjust
+			 * the list to remove the device.
+			 */
+			if (pdev != NULL)
+				pdev->next = dev->next;
+			else
+				pci_devices = dev->next;
 
-	    pbus = pbus->parent;
+			break;
+		}
+		pdev = dev;
 	}
+}
 
-	devnum &= 0x03;
-
-	/*
-	**    By default, get the PCI local domain IRQ value.
-	*/
-	irq = pci_localpirqs[devnum];
-
-	/*
-	**    Determine if the device is located in the
-	**    remote domain or not. We must find the
-	**    domain's bridge device located on bus 0.
-	*/
-	pbus = pdev->bus;
+void
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+	struct pci_bus  *pbus;          /* Parent bus structure pointer */
+	struct pci_dev	*tdev;		/* Temporary device structure */
+        unsigned int    devnum;         /* Accumulated device number */
+        unsigned char   intline;        /* Linux interrupt value */
+	unsigned char	intpin;		/* PCI interrupt pin */
+ 
+	/* Check for valid PCI dev pointer */
+	if (dev == NULL) return;
+
+	/* Fill our temporary device, and get the device number */
+	*tdev = *dev;
+	devnum = PCI_SLOT(tdev->devfn);
+
+	/* Read the interrupt pin of the device and adjust for indexing */
+	pcibios_read_config_byte(tdev->bus->number, tdev->devfn,
+				PCI_INTERRUPT_PIN, &intpin);
 
-	while (pbus->primary != 0)
-	    pbus = pbus->parent;
+	/* If device doesn't request an interrupt, return */
+	if ( (intpin < 1) || (intpin > 4) )
+		return;
 
-	/*
-	**    Check the device/function of domain's bridge
-	**    device against the remote device/function.
-	**    If the same, then the device is located in
-	**    the remote domain. Thus, get the PCI remote
-	**    domain IRQ value.
-	*/
-	if ((pbus->self)->devfn == pci_remotedev)
-        irq = pci_remotepirqs[devnum];
+	intpin--;
 
-	/*
-	**    Validate the IRQ number.
-	*/
-	if (irq <= 255)
+	/* Walk up to bus 0, adjusting the interrupt pin for the standard
+	   PCI bus swizzle. */
+	do {
+		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+		pbus = tdev->bus;        /* up one level */
+		tdev = pbus->self;
+		devnum = PCI_SLOT(tdev->devfn);
+	} while(tdev->bus->number);
+
+	/* Use the primary interrupt inputs by default */
+	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+
+	/* If the board has secondary interrupt inputs, walk the bus and
+	   note the devfn of the bridge from bus 0.  If it is the same as
+	   the devfn of the bus bridge with secondary inputs, use those. */
+	if (mot_info[mot_entry].secondary_bridge_devfn)
 	{
-	    /*
-	    **    Set the device's Interrupt Line register
-	    **    to the IRQ number and save it in the
-	    **    device's structure.
-	    */
-
-	    pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, (u8)irq);
-
-	    pdev->irq = irq;
-
+		pbus = dev->bus;
+ 
+		while (pbus->primary != 0)
+			pbus = pbus->parent;
+ 
+		if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+			intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
 	}
-	return;
+	
+	/* Write calculated interrupt value to header and device list */
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)intline);
+	dev->irq = intline;
 }
 
 int motopenpic_to_irq(int n)
@@ -1137,6 +1187,15 @@
 
 	prep_route_pci_interrupts();
 
+	/*
+	 * If MTX+, exclude the SL82C105 IDE controller so the driver
+	 * doesn't hang.
+	 */
+	if ( _prep_type == _PREP_Motorola )
+		if ( strstr(mot_info[mot_entry].name, "MTX Plus") )
+			/* On MTX+, SL82C105 is at IDSEL 0xb function 0x1 */
+			prep_exclude_pci_device(PCI_DEVFN(0xb, 0x1));
+
 	prep_pib_init();
 
 	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
@@ -1150,7 +1209,7 @@
 		       motopenpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
 
 		    pcibios_write_config_byte(dev->bus->number, dev->devfn, 
-					      PCI_INTERRUPT_PIN, dev->irq);
+					      PCI_INTERRUPT_LINE, dev->irq);
 		} else {
 			if (Motherboard_non0 != NULL)
 				Motherboard_non0(dev);
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- linux-2.2.17-pre2/arch/ppc/kernel/prep_setup.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Dec  3 22:05:46 2001
@@ -607,6 +607,7 @@
 	int i;
 
 	if (OpenPIC != NULL) {
+		open_pic.irq_offset = 16;
 		for ( i = 16 ; i < 36 ; i++ )
 			irq_desc[i].ctl = &open_pic;
 		openpic_init(1);
@@ -857,6 +858,7 @@
 	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;
 #endif
 #endif
 }
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- linux-2.2.17-pre2/arch/ppc/kernel/process.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/process.c	Mon Dec  3 22:05:46 2001
@@ -43,9 +43,11 @@
 #include <asm/mmu_context.h>
 
 int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
+int dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs);
 extern unsigned long _get_SP(void);
 
 struct task_struct *last_task_used_math = NULL;
+struct task_struct *last_task_used_altivec = NULL;
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
@@ -79,6 +81,31 @@
 	return 1;
 }
 
+#ifdef CONFIG_ALTIVEC
+int
+dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
+{
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+	memcpy(vrregs, &current->tss.vr[0], sizeof(*vrregs));
+	return 1;
+}
+
+void 
+enable_kernel_altivec(void)
+{
+#ifdef __SMP__
+	if (current->tss.regs && (current->tss.regs->msr & MSR_VEC))
+		giveup_altivec(current);
+	else
+		giveup_altivec(NULL);	/* just enable AltiVec for kernel - force */
+#else
+	giveup_altivec(last_task_used_altivec);
+#endif /* __SMP __ */
+	printk("MSR_VEC in enable_altivec_kernel\n");
+}
+#endif /* CONFIG_ALTIVEC */
+
 void
 enable_kernel_fp(void)
 {
@@ -194,22 +221,53 @@
 	_enable_interrupts(s);
 }
 
-void show_regs(struct pt_regs * regs)
+struct bits {
+	const char *name;
+	unsigned int bit;
+};
+
+void print_bits(unsigned int val, struct bits *bits)
+{
+	const char *sep = "";
+
+	printk("[");
+	for (; bits->bit != 0; ++bits) {
+		if (val & bits->bit) {
+			printk("%s", bits->name);
+			sep = ", ";
+		}
+	}
+	printk("]");
+}
+
+struct bits msr_bits[] = {
+	{"VEC", MSR_VEC},
+	{"EE", MSR_EE},
+	{"PR", MSR_PR},
+	{"FP", MSR_FP},
+	{"IR", MSR_IR},
+	{"DR", MSR_DR},
+	{"ME", MSR_ME},
+	{0, 0}
+};
+
+void show_regs(struct pt_regs *regs)
 {
 	int i;
 
 	printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
 	       regs->nip, regs->xer, regs->link, regs,regs->trap);
-	printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
-	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
-	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
-	       regs->msr&MSR_IR ? 1 : 0,
-	       regs->msr&MSR_DR ? 1 : 0);
+	printk("MSR: %08lx ", regs->msr);
+	print_bits(regs->msr, msr_bits);
+	printk("\n");
 	printk("TASK = %p[%d] '%s' mm->pgd %p ",
 	       current, current->pid, current->comm, current->mm->pgd);
 	printk("Last syscall: %ld ", current->tss.last_syscall);
-	printk("\nlast math %p", last_task_used_math);
-	
+	if (last_task_used_math)
+		printk("\nlast math %p", last_task_used_math);
+	if (last_task_used_altivec)
+		printk("\nlast altivec %p", last_task_used_altivec);
+
 #ifdef __SMP__	
 	printk(" CPU: %d last CPU: %d", current->processor,current->last_processor);
 #endif /* __SMP__ */
@@ -256,12 +314,16 @@
 {
 	if (last_task_used_math == current)
 		last_task_used_math = NULL;
+	if (last_task_used_altivec == current)
+		last_task_used_altivec = NULL;
 }
 
 void flush_thread(void)
 {
 	if (last_task_used_math == current)
 		last_task_used_math = NULL;
+	if (last_task_used_altivec == current)
+		last_task_used_altivec = NULL;
 }
 
 void
@@ -319,6 +381,19 @@
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
+#ifdef CONFIG_ALTIVEC
+	/*
+	 * copy altiVec info - assume lazy altiVec switch
+	 * - kumar
+	 */
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+
+	memcpy(&p->tss.vr, &current->tss.vr, sizeof(p->tss.vr));
+	p->tss.vscr = current->tss.vscr;
+	childregs->msr &= ~MSR_VEC;
+#endif /* CONFIG_ALTIVEC */
+
 	memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
 	p->tss.fpscr = current->tss.fpscr;
 	childregs->msr &= ~MSR_FP;
@@ -380,6 +455,8 @@
 	shove_aux_table(sp);
 	if (last_task_used_math == current)
 		last_task_used_math = 0;
+	if (last_task_used_altivec == current)
+		last_task_used_altivec = 0;
 	current->tss.fpscr = 0;
 }
 
@@ -439,6 +516,10 @@
 		goto out;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */ 
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
 	putname(filename);
 out:
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- linux-2.2.17-pre2/arch/ppc/kernel/prom.c	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/prom.c	Mon Dec  3 22:05:46 2001
@@ -26,6 +26,7 @@
 #include <asm/bootx.h>
 #include <asm/system.h>
 #include <asm/gemini.h>
+#include <asm/linux_logo.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -88,7 +89,7 @@
 char *of_stdout_device = 0;
 
 prom_entry prom = 0;
-ihandle prom_chosen = 0, prom_stdout = 0;
+ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0;
 int prom_version = 0;
 
 extern char *klimit;
@@ -100,33 +101,38 @@
 unsigned int rtas_size = 0;
 unsigned int old_rtas = 0;
 
+/* Set for a newworld machine */
+int use_of_interrupt_tree = 0;
+int pmac_newworld = 0;
+
 static struct device_node *allnodes = 0;
 
+#ifdef CONFIG_BOOTX_TEXT
+
 static void clearscreen(void);
 static void flushscreen(void);
 
-#ifdef CONFIG_BOOTX_TEXT
-
 void drawchar(char c);
 void drawstring(const char *c);
 static void drawhex(unsigned long v);
 static void scrollscreen(void);
 
 static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned long *base);
-static void draw_byte_16(unsigned char *bits, unsigned long *base);
-static void draw_byte_8(unsigned char *bits, unsigned long *base);
-
-static long				g_loc_X;
-static long				g_loc_Y;
-static long				g_max_loc_X;
-static long				g_max_loc_Y;
+static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
+
+/* We want those in the data section */
+static long				g_loc_X = 0;
+static long				g_loc_Y = 0;
+static long				g_max_loc_X = 0;
+static long				g_max_loc_Y = 0; 
 
 #define cmapsz	(16*256)
 
 static unsigned char vga_font[cmapsz];
 
-#endif
+#endif /* CONFIG_BOOTX_TEXT */
 
 
 static void *call_prom(const char *service, int nargs, int nret, ...);
@@ -136,15 +142,25 @@
 				  unsigned long, struct device_node ***);
 static unsigned long finish_node(struct device_node *, unsigned long,
 				 interpret_func *);
+static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
 static unsigned long check_display(unsigned long);
 static int prom_next_node(phandle *);
 static void *early_get_property(unsigned long, unsigned long, char *);
 
+#ifdef CONFIG_BOOTX_TEXT
+static void setup_disp_fake_bi(ihandle dp);
+static void prom_welcome(boot_infos_t* bi, unsigned long phys);
+#endif
+
 extern void enter_rtas(void *);
 extern unsigned long reloc_offset(void);
 
 extern char cmd_line[512];	/* XXX */
 boot_infos_t *boot_infos = 0;	/* init it so it's in data segment not bss */
+#ifdef CONFIG_BOOTX_TEXT
+boot_infos_t *disp_bi = 0;
+boot_infos_t fake_bi = {0,};
+#endif
 
 /*
  * prom_init() is called very early on, before the kernel text
@@ -237,7 +253,7 @@
 	if (RELOC(prom_stdout) == 0)
 	{
 #ifdef CONFIG_BOOTX_TEXT
-		if (RELOC(boot_infos) != 0)
+		if (RELOC(disp_bi) != 0)
 			drawstring(msg);
 #endif
 		return;
@@ -273,6 +289,7 @@
 	phandle node;
 	char type[16], *path;
 #endif	
+	int chrp = 0;
 	unsigned long mem;
 	ihandle prom_rtas, prom_mmu, prom_op;
 	unsigned long offset = reloc_offset();
@@ -299,22 +316,19 @@
 		unsigned long space;
 		unsigned long ptr, x;
 		char *model;
-#ifdef CONFIG_BOOTX_TEXT
-		unsigned long flags;
-#endif		
 
 		RELOC(boot_infos) = PTRUNRELOC(bi);
 		if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
 			bi->logicalDisplayBase = 0;
-
-		clearscreen();
-
 #ifdef CONFIG_BOOTX_TEXT
 		RELOC(g_loc_X) = 0;
 		RELOC(g_loc_Y) = 0;
 		RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
 		RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+		RELOC(disp_bi) = PTRUNRELOC(bi);
 		
+		clearscreen();
+
 		/* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since
 		   there is nothing much we can do with an incompatible version, except display
 		   a message and eventually hang the processor...
@@ -325,24 +339,10 @@
 		if (!BOOT_INFO_IS_COMPATIBLE(bi))
 			prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
 		
-		prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
-		prom_print(RELOC("\nstarted at       : 0x"));
-		drawhex(reloc_offset() + KERNELBASE);
-		prom_print(RELOC("\nlinked at        : 0x"));
-		drawhex(KERNELBASE);
-		prom_print(RELOC("\nframe buffer at  : 0x"));
-		drawhex((unsigned long)bi->dispDeviceBase);
-		prom_print(RELOC(" (phys), 0x"));
-		drawhex((unsigned long)bi->logicalDisplayBase);
-		prom_print(RELOC(" (log)"));
-		prom_print(RELOC("\nMSR              : 0x"));
-		__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory");
-		drawhex(flags);
-		prom_print(RELOC("\n\n"));
-#endif
-		/* Out of the #if/#endif since it flushes the clearscreen too */
+		prom_welcome(bi, phys);
 		flushscreen();
-		
+#endif /* CONFIG_BOOTX_TEXT */
+
 		/* New BootX enters kernel with MMU off, i/os are not allowed
 		   here. This hack will have been done by the boostrap anyway.
 		 */
@@ -420,12 +420,15 @@
 	    int sz;
 	    sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64);
 	    if (sz > 0) {
-	    	char *c;
-		for (c = model; *c; c++)
-		    if (*c >= '0' && *c <= '9') {
-			RELOC(prom_version) = *c - '0';
-			break;
-		    }
+		if ( strncmp(model,RELOC("IBM"),3) ) {
+	    	    char *c;
+		    for (c = model; *c; c++)
+		        if (*c >= '0' && *c <= '9') {
+			    RELOC(prom_version) = *c - '0';
+			    break;
+		        }
+		} else
+		    chrp = 1;
 	    }
 	}
 	if (RELOC(prom_version) >= 3)
@@ -533,6 +536,11 @@
 	    }
 	}
 	    
+#ifdef CONFIG_BOOTX_TEXT
+	if (!chrp && RELOC(prom_disp_node) != 0)
+		setup_disp_fake_bi(RELOC(prom_disp_node));
+#endif
+
 #ifdef CONFIG_SMP
 	/*
 	 * With CHRP SMP we need to use the OF to start the other
@@ -608,8 +616,8 @@
 		else
 			prom_print(RELOC("...failed\n"));
 	}
-#endif /* CONFIG_SMP */
 	
+#endif	
 	/* If OpenFirmware version >= 3, then use quiesce call */
 	if (RELOC(prom_version) >= 3) {
 	    prom_print(RELOC("Calling quiesce ...\n"));
@@ -618,9 +626,80 @@
 	    phys = offset + KERNELBASE;
 	}
 
+#ifdef CONFIG_BOOTX_TEXT
+	if (!chrp && RELOC(disp_bi)) {
+		RELOC(prom_stdout) = 0;
+		clearscreen();
+		prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
+		prom_print(RELOC("booting...\n"));
+	}
+#endif
+
 	return phys;
 }
 
+#ifdef CONFIG_BOOTX_TEXT
+__init static void
+prom_welcome(boot_infos_t* bi, unsigned long phys)
+{
+	unsigned long offset = reloc_offset();
+	unsigned long flags;
+	unsigned long pvr;
+	
+	prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+	prom_print(RELOC("\nstarted at       : 0x"));
+	drawhex(phys);
+	prom_print(RELOC("\nlinked at        : 0x"));
+	drawhex(KERNELBASE);
+	prom_print(RELOC("\nframe buffer at  : 0x"));
+	drawhex((unsigned long)bi->dispDeviceBase);
+	prom_print(RELOC(" (phys), 0x"));
+	drawhex((unsigned long)bi->logicalDisplayBase);
+	prom_print(RELOC(" (log)"));
+	prom_print(RELOC("\nMSR              : 0x"));
+	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+	drawhex(flags);
+	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+	pvr >>= 16;
+	if (pvr > 1) {
+	    prom_print(RELOC("\nHID0             : 0x"));
+	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+	    drawhex(flags);
+	}
+	if (pvr == 8 || pvr == 12) {
+	    prom_print(RELOC("\nICTC             : 0x"));
+	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+	    drawhex(flags);
+	}
+	prom_print(RELOC("\n\n"));
+}
+
+void showvalue(char *str, unsigned long val)
+{
+	drawstring(str);
+	drawhex(val);
+	drawstring("\n");
+}
+#endif
+
+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();
+
+	prom_args.service = RELOC("call-method");
+	prom_args.nargs = 6;
+	prom_args.nret = 1;
+	prom_args.args[0] = RELOC("color!");
+	prom_args.args[1] = ih;
+	prom_args.args[2] = (void *) i;
+	prom_args.args[3] = (void *) b;
+	prom_args.args[4] = (void *) g;
+	prom_args.args[5] = (void *) r;
+	RELOC(prom)(&prom_args);
+	return (int) prom_args.args[6];
+}
+
 /*
  * If we have a display that we don't know how to drive,
  * we will want to try to execute OF's open method for it
@@ -633,11 +712,32 @@
 static unsigned long
 check_display(unsigned long mem)
 {
+#ifdef CONFIG_FB
 	phandle node;
 	ihandle ih;
 	int i;
 	unsigned long offset = reloc_offset();
 	char type[16], *path;
+	static unsigned char default_colors[] = {
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0xaa,
+		0x00, 0xaa, 0x00,
+		0x00, 0xaa, 0xaa,
+		0xaa, 0x00, 0x00,
+		0xaa, 0x00, 0xaa,
+		0xaa, 0xaa, 0x00,
+		0xaa, 0xaa, 0xaa,
+		0x55, 0x55, 0x55,
+		0x55, 0x55, 0xff,
+		0x55, 0xff, 0x55,
+		0x55, 0xff, 0xff,
+		0xff, 0x55, 0x55,
+		0xff, 0x55, 0xff,
+		0xff, 0xff, 0x55,
+		0xff, 0xff, 0xff
+	};
+
+	RELOC(prom_disp_node) = 0;
 
 	for (node = 0; prom_next_node(&node); ) {
 		type[0] = 0;
@@ -660,6 +760,24 @@
 		}
 		prom_print(RELOC("... ok\n"));
 
+		if (RELOC(prom_disp_node) == 0)
+			RELOC(prom_disp_node) = node;
+			
+		/* Setup a useable color table when the appropriate
+		 * method is available. Should update this to set-colors */
+		for (i = 0; i < 32; i++)
+			if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
+					   RELOC(default_colors)[i*3+1],
+					   RELOC(default_colors)[i*3+2]) != 0)
+				break;
+
+		for (i = 0; i < LINUX_LOGO_COLORS; i++)
+			if (prom_set_color(ih, i + 32,
+					   RELOC(linux_logo_red)[i],
+					   RELOC(linux_logo_green)[i],
+					   RELOC(linux_logo_blue)[i]) != 0)
+				break;
+
 		/*
 		 * If this display is the device that OF is using for stdout,
 		 * move it to the front of the list.
@@ -676,9 +794,83 @@
 		if (RELOC(prom_num_displays) >= FB_MAX)
 			break;
 	}
+#endif /* CONFIG_FB */
 	return ALIGN(mem);
 }
 
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+#ifdef CONFIG_BOOTX_TEXT
+__init
+static void
+setup_disp_fake_bi(ihandle dp)
+{
+	unsigned int len;
+	int width = 640, height = 480, depth = 8, pitch;
+	unsigned  address;
+	boot_infos_t* bi;
+	unsigned long offset = reloc_offset();
+	
+	prom_print(RELOC("Initing fake screen\n"));
+
+	len = 0;
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
+	if (len == 0)
+		prom_print(RELOC("Warning: assuming display depth = 8\n"));
+	else
+		depth = len;
+	width = len = 0;
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len));
+	width = len;
+	if (width == 0) {
+		prom_print(RELOC("Failed to get width\n"));
+		return;
+	}
+	height = len = 0;
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len));
+	height = len;
+	if (height == 0) {
+		prom_print(RELOC("Failed to get height\n"));
+		return;
+	}
+	pitch = len = 0;
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
+	pitch = len;
+	if (pitch == 0) {
+		prom_print(RELOC("Failed to get pitch\n"));
+		return;
+	}
+	address = len = 0;
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
+	address = len;
+	if (address == 0) {
+		prom_print(RELOC("Failed to get address\n"));
+		return;
+	}
+#if 0
+	/* kludge for valkyrie */
+	if (strcmp(dp->name, "valkyrie") == 0) 
+	    address += 0x1000;
+    }
+#endif
+ 
+    RELOC(disp_bi) = &fake_bi;
+    bi = PTRRELOC((&fake_bi));
+    RELOC(g_loc_X) = 0;
+    RELOC(g_loc_Y) = 0;
+    RELOC(g_max_loc_X) = width / 8;
+    RELOC(g_max_loc_Y) = height / 16;
+    bi->logicalDisplayBase = (unsigned char *)address;
+    bi->dispDeviceBase = (unsigned char *)address;
+    bi->dispDeviceRowBytes = pitch;
+    bi->dispDeviceDepth = depth;
+    bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+    bi->dispDeviceRect[2] = width;
+    bi->dispDeviceRect[3] = height;
+}
+#endif
+
 __init
 static int
 prom_next_node(phandle *nodep)
@@ -813,6 +1005,32 @@
 finish_device_tree(void)
 {
 	unsigned long mem = (unsigned long) klimit;
+#if 0
+	char* model;
+	
+	/* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not.
+	 * This code was only tested with Core99 machines so far, but should be easily
+	 * adapted to older newworld machines (iMac, B&W G3, Lombard).
+	 */
+	model = get_property(allnodes, "model", 0);
+	if ((boot_infos == 0) && model && (
+		strcmp(model, "PowerBook2,1") == 0 ||
+		strcmp(model, "PowerBook3,1") == 0 ||
+		strcmp(model, "PowerMac2,1") == 0 ||
+		strcmp(model, "PowerMac3,1") == 0))
+ 		use_of_interrupt_tree = 1;
+#endif 	
+	/* All newworld machines now use the interrupt tree */
+	struct device_node *np = allnodes;
+	while(np) {
+		if (get_property(np, "interrupt-parent", 0)) {
+			pmac_newworld = 1;
+			break;
+		}
+		np = np->allnext;
+	}
+	if (boot_infos == 0 && pmac_newworld)
+		use_of_interrupt_tree = 1;
 
 	mem = finish_node(allnodes, mem, NULL);
 	printk(KERN_INFO "device tree used %lu bytes\n",
@@ -854,6 +1072,9 @@
 	if (ifunc != NULL) {
 		mem_start = ifunc(np, mem_start);
 	}
+	if (use_of_interrupt_tree) {
+		mem_start = finish_node_interrupts(np, mem_start);
+	}
 
 	/* the f50 sets the name to 'display' and 'compatible' to what we
 	 * expect for the name -- Cort
@@ -900,6 +1121,132 @@
 	return mem_start;
 }
 
+/* This routine walks the interrupt tree for a given device node and gather 
+ * all necessary informations according to the draft interrupt mapping
+ * for CHRP. The current version was only tested on Apple "Core99" machines
+ * and may not handle cascaded controllers correctly.
+ */
+__init
+static unsigned long
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+	/* Finish this node */
+	unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
+	phandle *parent;
+	struct device_node *node, *parent_node;
+	int l, isize, ipsize, asize, map_size, regpsize;
+
+	/* Currently, we don't look at all nodes with no "interrupts" property */
+	interrupts = (unsigned int *)get_property(np, "interrupts", &l);
+	if (interrupts == NULL)
+		return mem_start;
+	ipsize = l>>2;
+
+	reg = (unsigned int *)get_property(np, "reg", &l);
+	regpsize = l>>2;
+
+	/* We assume default interrupt cell size is 1 (bugus ?) */
+	isize = 1;
+	node = np;
+	
+	do {
+	    /* We adjust the cell size if the current parent contains an #interrupt-cells
+	     * property */
+	    isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
+	    if (isizep)
+	    	isize = *isizep;
+
+	    /* We don't do interrupt cascade (ISA) for now, we stop on the first 
+	     * controller found
+	     */
+	    if (get_property(node, "interrupt-controller", &l)) {
+	    	int i,j;
+	    	np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = ipsize / isize;
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		for (i = 0; i < np->n_intrs; ++i) {
+		    np->intrs[i].line = *interrupts++;
+		    np->intrs[i].sense = 0;
+		    if (isize > 1)
+		        np->intrs[i].sense = *interrupts++;
+		    for (j=2; j<isize; j++)
+		    	interrupts++;
+		}
+		return mem_start;
+	    }
+	    /* We lookup for an interrupt-map. This code can only handle one interrupt
+	     * per device in the map. We also don't handle #address-cells in the parent
+	     * I skip the pci node itself here, may not be necessary but I don't like it's
+	     * reg property.
+	     */
+	    if (np != node)
+	        map = (unsigned int *)get_property(node, "interrupt-map", &l);
+	     else
+	     	map = NULL;
+	    if (map && l) {
+	    	int i, found, temp_isize;
+	        map_size = l>>2;
+	        map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
+	        asizep = (unsigned int *)get_property(node, "#address-cells", &l);
+	        if (asizep && l == sizeof(unsigned int))
+	            asize = *asizep;
+	        else
+	            asize = 0;
+	        found = 0;
+	        while(map_size>0 && !found) {
+	            found = 1;
+	            for (i=0; i<asize; i++) {
+	            	unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
+	            	if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
+	           	    found = 0;
+	           	map++;
+	           	map_size--;
+	            }
+	            for (i=0; i<isize; i++) {
+	            	unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
+	            	if ((mask & *map) != (mask & interrupts[i]))
+	            	    found = 0;
+	            	map++;
+	            	map_size--;
+	            }
+	            parent = *((phandle *)(map));
+	            map+=1; map_size-=1;
+	            parent_node = find_phandle(parent);
+	            temp_isize = isize;
+	            if (parent_node) {
+			isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
+	    		if (isizep)
+	    		    temp_isize = *isizep;
+	            }
+	            if (!found) {
+	            	map += temp_isize;
+	            	map_size-=temp_isize;
+	            }
+	        }
+	        if (found) {
+	            node = parent_node;
+	            reg = NULL;
+	            regpsize = 0;
+	            interrupts = (unsigned int *)map;
+	            ipsize = temp_isize*1;
+		    continue;
+	        }
+	    }
+	    /* We look for an explicit interrupt-parent.
+	     */
+	    parent = (phandle *)get_property(node, "interrupt-parent", &l);
+	    if (parent && (l == sizeof(phandle)) &&
+	    	(parent_node = find_phandle(*parent))) {
+	    	node = parent_node;
+	    	continue;
+	    }
+	    /* Default, get real parent */
+	    node = node->parent;
+	} while(node);
+
+	return mem_start;
+}
+
 /*
  * When BootX makes a copy of the device tree from the MacOS
  * Name Registry, it is in the format we use but all of the pointers
@@ -958,6 +1305,9 @@
 		mem_start += i * sizeof(struct address_range);
 	}
 
+	if (use_of_interrupt_tree)
+		return mem_start;
+
 	/*
 	 * If the pci host bridge has an interrupt-map property,
 	 * look for our node in it.
@@ -967,14 +1317,28 @@
 		get_property(np->parent, "interrupt-map", &ml)) != 0
 	    && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
 		unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
+		unsigned int cell_size;
+		struct device_node* np2;
+		/* This is hackish, but is only used for BootX booting */
+		cell_size = sizeof(struct pci_intr_map);
+		np2 = np->parent;
+		while(np2) {
+			if (device_is_compatible(np2, "uni-north")) {
+				cell_size += 4;
+				break;
+			}
+			np2 = np2->parent;
+		}
 		np->n_intrs = 0;
 		np->intrs = (struct interrupt_info *) mem_start;
-		for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) {
-			if (imp[i].addr.a_hi == devfn) {
-				np->intrs[np->n_intrs].line = imp[i].intr;
-				np->intrs[np->n_intrs].sense = 0;
+		for (i = 0; (ml -= cell_size) >= 0; ++i) {
+			if (imp->addr.a_hi == devfn) {
+				np->intrs[np->n_intrs].line = imp->intr;
+				np->intrs[np->n_intrs].sense = 0; /* FIXME */
 				++np->n_intrs;
 			}
+			imp = (struct pci_intr_map *)(((unsigned int)imp)
+				+ cell_size);
 		}
 		if (np->n_intrs == 0)
 			np->intrs = 0;
@@ -1031,6 +1395,9 @@
 		mem_start += i * sizeof(struct address_range);
 	}
 
+	if (use_of_interrupt_tree)
+		return mem_start;
+
 	ip = (int *) get_property(np, "AAPL,interrupts", &l);
 	if (ip == 0)
 		ip = (int *) get_property(np, "interrupts", &l);
@@ -1054,13 +1421,14 @@
 	struct reg_property *rp;
 	struct address_range *adr;
 	unsigned long base_address;
-	int i, l, *ip;
+	int i, l, keylargo, *ip;
 	struct device_node *db;
 
 	base_address = 0;
 	for (db = np->parent; db != NULL; db = db->parent) {
 		if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
 			base_address = db->addrs[0].address;
+			keylargo = device_is_compatible(db, "Keylargo");
 			break;
 		}
 	}
@@ -1080,6 +1448,9 @@
 		mem_start += i * sizeof(struct address_range);
 	}
 
+	if (use_of_interrupt_tree)
+		return mem_start;
+
 	ip = (int *) get_property(np, "interrupts", &l);
 	if (ip == 0)
 		ip = (int *) get_property(np, "AAPL,interrupts", &l);
@@ -1088,9 +1459,15 @@
 		if (_machine == _MACH_Pmac) {
 			/* for the iMac */
 			np->n_intrs = l / sizeof(int);
+			/* Hack for BootX on Core99 */
+			if (keylargo)
+				np->n_intrs = np->n_intrs/2;
 			for (i = 0; i < np->n_intrs; ++i) {
 				np->intrs[i].line = *ip++;
-				np->intrs[i].sense = 0;
+				if (keylargo)
+					np->intrs[i].sense = *ip++;
+				else
+					np->intrs[i].sense = 0;
 			}
 		} else {
 			/* CHRP machines */
@@ -1130,6 +1507,9 @@
 		mem_start += i * sizeof(struct address_range);
 	}
 
+	if (use_of_interrupt_tree)
+		return mem_start;
+ 
 	ip = (int *) get_property(np, "interrupts", &l);
 	if (ip != 0) {
 		np->intrs = (struct interrupt_info *) mem_start;
@@ -1167,6 +1547,9 @@
 		mem_start += i * sizeof(struct address_range);
 	}
 
+	if (use_of_interrupt_tree)
+		return mem_start;
+
 	ip = (int *) get_property(np, "AAPL,interrupts", &l);
 	if (ip == 0)
 		ip = (int *) get_property(np, "interrupts", &l);
@@ -1223,6 +1606,49 @@
 	return head;
 }
 
+/* Finds a device node given its PCI bus number, device number
+ * and function number
+ */
+__openfirmware
+struct device_node *
+find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn)
+{
+	struct device_node* np;
+	unsigned int *reg;
+	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)
+			continue;
+		reg = (unsigned int *) get_property(np, "reg", &l);
+		if (reg == 0 || l < sizeof(struct reg_property))
+			continue;
+		if (((reg[0] >> 8) & 0xff) == dev_fn && ((reg[0] >> 16) & 0xff) == bus)
+			break;
+	}
+	return np;
+}
+
+/*
+ * Returns all nodes linked together
+ */
+__openfirmware
+struct device_node *
+find_all_nodes(void)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		*prevp = np;
+		prevp = &np->next;
+	}
+	*prevp = 0;
+	return head;
+}
+
 /* Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
@@ -1424,18 +1850,44 @@
 	prom_exit();
 }
 
-#ifdef CONFIG_XMON
+/* Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+__openfirmware
+int
+machine_is_compatible(const char *compat)
+{
+	struct device_node *root;
+	
+	root = find_path_device("/");
+	if (root == 0)
+		return 0;
+	return device_is_compatible(root, compat);
+}
+
+
+#ifdef CONFIG_BOOTX_TEXT
+
+/* Here's a small text engine to use during early boot or for debugging purposes
+ * 
+ * todo:
+ * 
+ *  - build some kind of vgacon with it to enable early printk
+ *  - move to a separate file
+ *  - add a few video driver hooks to keep in sync with display
+ *    changes.
+ */
+
 __init
 void
 map_bootx_text(void)
 {
-	if (boot_infos == 0)
+	if (disp_bi == 0)
 		return;
-	boot_infos->logicalDisplayBase =
-		ioremap((unsigned long) boot_infos->dispDeviceBase,
-			boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]);
+	disp_bi->logicalDisplayBase =
+		ioremap((unsigned long) disp_bi->dispDeviceBase,
+			disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
 }
-#endif /* CONFIG_XMON */
 
 /* Calc the base address of a given point (x,y) */
 __pmac
@@ -1457,7 +1909,7 @@
 clearscreen(void)
 {
 	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
+	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
 	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
 	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 					(bi->dispDeviceDepth >> 3)) >> 2;
@@ -1482,7 +1934,7 @@
 flushscreen(void)
 {
 	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
+	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
 	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
 	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
 					(bi->dispDeviceDepth >> 3)) >> 2;
@@ -1499,29 +1951,12 @@
 	}
 }
 
-/* Indicates whether the root node has a given value in its
- * compatible property.
- */
-__openfirmware
-int
-machine_is_compatible(const char *compat)
-{
-	struct device_node *root;
-	
-	root = find_path_device("/");
-	if (root == 0)
-		return 0;
-	return device_is_compatible(root, compat);
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-
 __pmac
 static void
 scrollscreen(void)
 {
 	unsigned long offset		= reloc_offset();
-	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
+	boot_infos_t* bi		= PTRRELOC(RELOC(disp_bi));
 	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
 	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
 	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
@@ -1611,19 +2046,20 @@
 draw_byte(unsigned char c, long locX, long locY)
 {
 	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(boot_infos));
+	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
 	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
 	unsigned char *font	= &RELOC(vga_font)[((unsigned long)c) * 16];
+	int rb			= bi->dispDeviceRowBytes;
 	
 	switch(bi->dispDeviceDepth) {
 		case 32:
-			draw_byte_32(font, (unsigned long *)base);
+			draw_byte_32(font, (unsigned long *)base, rb);
 			break;
 		case 16:
-			draw_byte_16(font, (unsigned long *)base);
+			draw_byte_16(font, (unsigned long *)base, rb);
 			break;
 		case 8:
-			draw_byte_8(font, (unsigned long *)base);
+			draw_byte_8(font, (unsigned long *)base, rb);
 			break;
 		default:
 			break;
@@ -1661,10 +2097,8 @@
 
 __pmac
 static void
-draw_byte_32(unsigned char *font, unsigned long *base)
+draw_byte_32(unsigned char *font, unsigned long *base, int rb)
 {
-	unsigned long offset = reloc_offset();
-	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
 	int l, bits;	
 	int fg = 0xFFFFFFFFUL;
 	int bg = 0x00000000UL;
@@ -1681,19 +2115,18 @@
 		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
 		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
 		base[7] = (-(bits & 1) & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+		base = (unsigned long *) ((char *)base + rb);
 	}
 }
 
 __pmac
 static void
-draw_byte_16(unsigned char *font, unsigned long *base)
+draw_byte_16(unsigned char *font, unsigned long *base, int rb)
 {
-	unsigned long offset = reloc_offset();
-	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
 	int l, bits;	
 	int fg = 0xFFFFFFFFUL;
 	int bg = 0x00000000UL;
+	unsigned long offset = reloc_offset();
 	unsigned long *eb = RELOC(expand_bits_16);
 
 	for (l = 0; l < 16; ++l)
@@ -1703,19 +2136,18 @@
 		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
 		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
 		base[3] = (eb[bits & 3] & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+		base = (unsigned long *) ((char *)base + rb);
 	}
 }
 
 __pmac
 static void
-draw_byte_8(unsigned char *font, unsigned long *base)
+draw_byte_8(unsigned char *font, unsigned long *base, int rb)
 {
-	unsigned long offset = reloc_offset();
-	boot_infos_t* bi		= PTRRELOC(RELOC(boot_infos));
 	int l, bits;	
 	int fg = 0x0F0F0F0FUL;
 	int bg = 0x00000000UL;
+	unsigned long offset = reloc_offset();
 	unsigned long *eb = RELOC(expand_bits_8);
 
 	for (l = 0; l < 16; ++l)
@@ -1723,7 +2155,7 @@
 		bits = *font++;
 		base[0] = (eb[bits >> 4] & fg) ^ bg;
 		base[1] = (eb[bits & 0xf] & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes);
+		base = (unsigned long *) ((char *)base + rb);
 	}
 }
 
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- linux-2.2.17-pre2/arch/ppc/kernel/setup.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/setup.c	Mon Dec  3 22:05:46 2001
@@ -68,6 +68,13 @@
                       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
+
 extern boot_infos_t *boot_infos;
 extern char cmd_line[512];
 char saved_command_line[256];
@@ -256,6 +263,9 @@
 		case 10:
 			len += sprintf(len+buffer, "604ev5 (MachV)\n");
 			break;
+		case 12:
+			len += sprintf(len+buffer, "7400 (G4)\n");
+			break;
 		case 50:
 			len += sprintf(len+buffer, "821\n");
 		case 80:
@@ -456,11 +466,15 @@
 			char *p;
 			
 #ifdef CONFIG_BLK_DEV_INITRD
-			if (r3 - KERNELBASE < 0x800000
-			    && r4 != 0 && r4 != 0xdeadbeef) {
+			/* Removed check < 0x800000, yaboot loads the kernel at +16Mb
+			 * and the ramdisk _after_ the kernel */
+			if (r3 && r4 && r4 != 0xdeadbeef) {
+				if (r3 < KERNELBASE)
+					r3 += KERNELBASE;
 				initrd_start = r3;
 				initrd_end = r3 + r4;
 				ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+				initrd_below_start_ok = 1;
 			}
 #endif
 			cmd_line[0] = 0;
@@ -538,7 +552,7 @@
 /* Checks "l2cr=xxxx" command-line option */
 void ppc_setup_l2cr(char *str, int *ints)
 {
-	if ( (_get_PVR() >> 16) == 8)
+	if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) )
 	{
 		unsigned long val = simple_strtoul(str, NULL, 0);
 		printk(KERN_INFO "l2cr set to %lx\n", val);
@@ -564,14 +578,19 @@
 	extern unsigned long find_available_memory(void);
 	extern unsigned long *end_of_DRAM;
 
+#ifdef CONFIG_BOOTX_TEXT
+	map_bootx_text();
+#endif
+
 #ifdef CONFIG_XMON
-	extern void xmon_map_scc(void);
-	char *p;
+	{
+		char *p;
 
-	xmon_map_scc();
-	p = strstr(cmd_line, "xmon");
-	if (p != NULL && (p == cmd_line || p[-1] == ' '))
-		xmon(0);
+		xmon_map_scc();
+		p = strstr(cmd_line, "xmon");
+		if (p != NULL && (p == cmd_line || p[-1] == ' '))
+			xmon(0);
+	}
 #endif /* CONFIG_XMON */
  
 	/* reboot on panic */	
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- linux-2.2.17-pre2/arch/ppc/kernel/signal.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/kernel/signal.c	Mon Dec  3 22:05:46 2001
@@ -220,6 +220,10 @@
 		sr = (struct sigregs *) sigctx.regs;
 		if (regs->msr & MSR_FP )
 			giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+		if (regs->msr & MSR_VEC)
+			giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
 		if (copy_from_user(saved_regs, &sr->gp_regs,
 				   sizeof(sr->gp_regs)))
 			goto badframe;
@@ -268,6 +272,10 @@
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
 	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
 	    || __copy_to_user(&frame->fp_regs, current->tss.fpr,
 			      ELF_NFPREG * sizeof(double))
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- linux-2.2.17-pre2/arch/ppc/kernel/smp.c	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/kernel/smp.c	Mon Dec  3 22:05:46 2001
@@ -7,7 +7,7 @@
  * deal of code from the sparc and intel versions.
  *
  * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
- * (troy@microux.com, hozer@drgw.net)
+ * (troy@blacklablinux.com, hozer@drgw.net)
  */
 
 #include <linux/kernel.h>
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- linux-2.2.17-pre2/arch/ppc/kernel/syscalls.c	Wed Aug 25 17:29:46 1999
+++ linux/arch/ppc/kernel/syscalls.c	Mon Dec  3 22:05:46 2001
@@ -246,9 +246,14 @@
 
 asmlinkage int sys_uname(struct old_utsname * name)
 {
-	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
-		return 0;
-	return -EFAULT;
+	int err;
+	
+	if (!name)
+		return -EFAULT;
+	down(&uts_sem);
+	err = copy_to_user(name, &system_utsname, sizeof (*name));
+	up(&uts_sem);
+	return err ? -EFAULT : 0;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -260,6 +265,7 @@
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 		return -EFAULT;
   
+  	down(&uts_sem);
 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
 	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
@@ -271,6 +277,7 @@
 	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	error = __put_user(0,name->machine+__OLD_UTS_LEN);
 	error = error ? -EFAULT : 0;
+	up(&uts_sem);
 
 	return error;
 }
diff -urN linux-2.2.17-pre2/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- linux-2.2.17-pre2/arch/ppc/kernel/traps.c	Fri Jun  4 13:30:47 1999
+++ linux/arch/ppc/kernel/traps.c	Mon Dec  3 22:05:46 2001
@@ -100,26 +100,27 @@
 			return;
 		}
 #endif
-		printk("Machine check in kernel mode.\n");
-		printk("Caused by (from msr): ");
-		printk("regs %p ",regs);
-		switch( regs->msr & 0x0000F000)
-		{
-		case (1<<12) :
-			printk("Machine check signal - probably due to mm fault\n"
-				"with mmu off\n");
+		printk("Machine check in kernel mode.  (regs at %p)\n", regs);
+		printk("Caused by (from srr1): ");
+		switch( regs->msr & 0x001F0000) {
+		case 0x100000:
+			printk("L2 data cache parity error\n");
 			break;
-		case (1<<13) :
+		case 0x80000:
+			printk("Machine check signal\n");
+			printk("(probably due to access of bad physical address\n");
+			break;
+		case 0x40000:
 			printk("Transfer error ack signal\n");
 			break;
-		case (1<<14) :
+		case 0x20000:
 			printk("Data parity signal\n");
 			break;
-		case (1<<15) :
+		case 0x10000:
 			printk("Address parity signal\n");
 			break;
 		default:
-			printk("Unknown values in msr\n");
+			printk("Unknown values in srr1\n");
 		}
 		show_regs(regs);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
diff -urN linux-2.2.17-pre2/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S
--- linux-2.2.17-pre2/arch/ppc/lib/string.S	Tue Oct 26 17:53:39 1999
+++ linux/arch/ppc/lib/string.S	Mon Dec  3 22:05:46 2001
@@ -12,6 +12,11 @@
 #include <asm/processor.h>
 #include <asm/errno.h>
 
+CACHELINE_BYTES = 32
+LG_CACHELINE_BYTES = 5
+CACHELINE_MASK = 0x1f
+CACHELINE_WORDS = 8
+
 	.globl	strcpy
 strcpy:
 	addi	r5,r3,-1
@@ -82,7 +87,35 @@
 	andi.	r0,r6,3
 	add	r5,r0,r5
 	subf	r6,r0,r6
-	rlwinm	r0,r5,32-2,2,31
+#if 0	/* Clever, but breaks fb stuff -- paulus */
+/*
+ * Use dcbz on the complete cache lines in the destination if
+ * we are setting to zero.  This requires that the destination
+ * area is cacheable.  -- paulus
+ */
+	cmpwi	0,r4,0
+	bne	2f
+	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
+	add	r8,r7,r5
+	srwi	r9,r8,LG_CACHELINE_BYTES
+	addic.	r9,r9,-1	/* total number of complete cachelines */
+	ble	2f
+	xori	r0,r7,CACHELINE_MASK & ~3
+	srwi.	r0,r0,2
+	beq	3f
+	mtctr	r0
+4:	stwu	r4,4(r6)
+	bdnz	4b
+3:	mtctr	r9
+	li	r7,4
+10:	dcbz	r7,r6
+	addi	r6,r6,CACHELINE_BYTES
+	bdnz	10b
+	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
+	addi	r5,r5,4
+2:
+#endif
+	srwi	r0,r5,2
 	mtctr	r0
 	bdz	6f
 1:	stwu	r4,4(r6)
@@ -107,11 +140,94 @@
 memmove:
 	cmplw	0,r3,r4
 	bgt	backwards_memcpy
-	/* fall through */
+	b	forwards_memcpy
 
 	.globl	memcpy
 memcpy:
-	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+#if 0	/* Clever, but will probably break fb stuff -- paulus */
+/*
+ * This version uses dcbz on the complete cache lines in the
+ * destination area to reduce memory traffic.  This requires that
+ * the destination area is cacheable.
+ * We only use this version if the source and dest don't overlap.
+ * -- paulus.
+ */
+	add	r7,r3,r5		/* test if the src & dst overlap */
+	add	r8,r4,r5
+	cmplw	0,r4,r7
+	cmplw	1,r3,r8
+	crand	0,0,4			/* cr0.lt &= cr1.lt */
+	blt	forwards_memcpy		/* if regions overlap */
+
+	addi	r4,r4,-4
+	addi	r6,r3,-4
+	neg	r0,r3
+	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
+	beq	58f
+
+	cmplw	0,r5,r0			/* is this more than total to do? */
+	blt	63f			/* if not much to do */
+	andi.	r8,r0,3			/* get it word-aligned first */
+	subf	r5,r0,r5
+	mtctr	r8
+	beq+	61f
+70:	lbz	r9,4(r4)		/* do some bytes */
+	stb	r9,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	70b
+61:	srwi.	r0,r0,2
+	mtctr	r0
+	beq	58f
+72:	lwzu	r9,4(r4)		/* do some words */
+	stwu	r9,4(r6)
+	bdnz	72b
+
+58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
+	li	r11,4
+	mtctr	r0
+	beq	63f
+53:	dcbz	r11,r6
+	lwz	r7,4(r4)
+	lwz	r8,8(r4)
+	lwz	r9,12(r4)
+	lwzu	r10,16(r4)
+	stw	r7,4(r6)
+	stw	r8,8(r6)
+	stw	r9,12(r6)
+	stwu	r10,16(r6)
+	lwz	r7,4(r4)
+	lwz	r8,8(r4)
+	lwz	r9,12(r4)
+	lwzu	r10,16(r4)
+	stw	r7,4(r6)
+	stw	r8,8(r6)
+	stw	r9,12(r6)
+	stwu	r10,16(r6)
+	bdnz	53b
+
+63:	srwi.	r0,r5,2
+	mtctr	r0
+	beq	64f
+30:	lwzu	r0,4(r4)
+	stwu	r0,4(r6)
+	bdnz	30b
+
+64:	andi.	r0,r5,3
+	mtctr	r0
+	beq+	65f
+40:	lbz	r0,4(r4)
+	stb	r0,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	40b
+65:	blr
+#endif
+
+	.global	forwards_memcpy
+forwards_memcpy:
+	srwi.	r7,r5,3
 	addi	r6,r3,-4
 	addi	r4,r4,-4
 	beq	2f			/* if less than 8 bytes to do */
@@ -218,106 +334,167 @@
 
 	.globl	__copy_tofrom_user
 __copy_tofrom_user:
-	srwi.	r7,r5,3
-	addi	r6,r3,-4
 	addi	r4,r4,-4
-	li	r3,0		/* success return value */
-	beq	2f		/* if less than 8 bytes to do */
-	andi.	r0,r6,3		/* get dest word aligned */
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,4(r4)
-11:	lwzu	r8,8(r4)
-12:	stw	r7,4(r6)
-13:	stwu	r8,8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-14:	lwzu	r0,4(r4)
-	addi	r5,r5,-4
-15:	stwu	r0,4(r6)
-3:	cmpwi	0,r5,0		/* do 1 byte at a time for the remainder */
-	beqlr
-	mtctr	r5
-	addi	r4,r4,3
-	addi	r6,r6,3
-4:	lbzu	r0,1(r4)
-16:	stbu	r0,1(r6)
-	bdnz	4b
-	blr
-5:	subfic	r0,r0,4		/* copy bytes until we have the */
-	mtctr	r0		/* destination 4-byte aligned */
-	subf	r5,r0,r5
-6:	lbz	r7,4(r4)
+	addi	r6,r3,-4
+	neg	r0,r3
+	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
+	beq	58f
+
+	cmplw	0,r5,r0			/* is this more than total to do? */
+	blt	63f			/* if not much to do */
+	andi.	r8,r0,3			/* get it word-aligned first */
+	mtctr	r8
+	beq+	61f
+70:	lbz	r9,4(r4)		/* do some bytes */
+71:	stb	r9,4(r6)
 	addi	r4,r4,1
-17:	stb	r7,4(r6)
 	addi	r6,r6,1
-	bdnz	6b
-	srwi.	r7,r5,3
-	beq	2b
-	mtctr	r7
-	b	1b
-/* we come here on a fault in the 8-byte-at-a-time loop */
-88:	subi	r4,r4,8		/* compensate for the lwzu */
-98:	mfctr	r0
-	rlwimi	r5,r0,3,0,28	/* use the byte-at-a-time loop to */
-	b	3b		/* copy up to the byte at fault */
-/* here on a write fault in the single-word copy */
-96:	subi	r4,r4,4
-	b	3b
-/* here on a read fault in the initial single-byte copy */
-90:	mfctr	r3
-	add	r3,r3,r5
-	b	70f
-/* here on a read fault in the final single-byte copy */
-99:	mfctr	r3
-	subi	r6,r6,3
-/* clear out the rest of the destination: r3 bytes starting at 4(r6) */
-70:	li	r0,0
-	mr.	r5,r3
-	beq	76f
-71:	andi.	r4,r6,3
-	beq	72f
-77:	stb	r0,4(r6)
+	bdnz	70b
+61:	subf	r5,r0,r5
+	srwi.	r0,r0,2
+	mtctr	r0
+	beq	58f
+72:	lwzu	r9,4(r4)		/* do some words */
+73:	stwu	r9,4(r6)
+	bdnz	72b
+
+58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
+	li	r11,4
+	mtctr	r0
+	beq	63f
+53:	dcbz	r11,r6
+10:	lwz	r7,4(r4)
+11:	lwz	r8,8(r4)
+12:	lwz	r9,12(r4)
+13:	lwzu	r10,16(r4)
+14:	stw	r7,4(r6)
+15:	stw	r8,8(r6)
+16:	stw	r9,12(r6)
+17:	stwu	r10,16(r6)
+20:	lwz	r7,4(r4)
+21:	lwz	r8,8(r4)
+22:	lwz	r9,12(r4)
+23:	lwzu	r10,16(r4)
+24:	stw	r7,4(r6)
+25:	stw	r8,8(r6)
+26:	stw	r9,12(r6)
+27:	stwu	r10,16(r6)
+	bdnz	53b
+
+63:	srwi.	r0,r5,2
+	mtctr	r0
+	beq	64f
+30:	lwzu	r0,4(r4)
+31:	stwu	r0,4(r6)
+	bdnz	30b
+
+64:	andi.	r0,r5,3
+	mtctr	r0
+	beq+	65f
+40:	lbz	r0,4(r4)
+41:	stb	r0,4(r6)
+	addi	r4,r4,1
 	addi	r6,r6,1
-	addic.	r5,r5,-1
-	bne	71b
-72:	srwi.	r7,r5,2
-	beq	73f
-	mtctr	r7
-74:	stwu	r0,4(r6)
-	bdnz	74b
-73:	andi.	r5,r5,3
-	beq	76f
-	mtctr	r5
-	addi	r6,r6,3
-75:	stbu	r0,1(r6)
-	bdnz	75b
-76:	blr
-/* here on a write fault in the initial single-byte copy */
-80:	mfctr	r3
-	add	r3,r3,r5
-	blr
-/* here on a write fault in the final single-byte copy */
-81:	mfctr	r3
+	bdnz	40b
+65:	li	r3,0
 	blr
 
+/* read fault, initial single-byte copy */
+100:	li	r4,0
+	b	90f
+/* write fault, initial single-byte copy */
+101:	li	r4,1
+90:	subf	r5,r8,r5
+	li	r3,0
+	b	99f
+/* read fault, initial word copy */
+102:	li	r4,0
+	b	91f
+/* write fault, initial word copy */
+103:	li	r4,1
+91:	li	r3,2
+	b	99f
+/* read fault in 2nd half of cacheline loop */
+106:	addi	r5,r5,-16
+/* read fault in 1st half of cacheline loop */
+104:	li	r4,0
+	b	92f
+/* write fault in 2nd half of cacheline loop */
+107:	addi	r5,r5,-16
+/* fault on dcbz (effectively a write fault) */
+/* or write fault in 1st half of cacheline loop */
+105:	li	r4,1
+92:	li	r3,LG_CACHELINE_BYTES
+	b	99f
+/* read fault in final word loop */
+108:	li	r4,0
+	b	93f
+/* write fault in final word loop */
+109:	li	r4,1
+93:	andi.	r5,r5,3
+	li	r3,2
+	b	99f
+/* read fault in final byte loop */
+110:	li	r4,0
+	b	94f
+/* write fault in final byte loop */
+111:	li	r4,1
+94:	li	r5,0
+	li	r3,0
+/*
+ * At this stage the number of bytes not copied is
+ * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ */
+99:	mfctr	r0
+	slw	r3,r0,r3
+	add	r3,r3,r5
+	cmpwi	0,r4,0
+	bne	120f
+/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+	srwi.	r0,r3,2
+	li	r9,0
+	mtctr	r0
+	beq	113f
+112:	stwu	r9,4(r6)
+	bdnz	112b
+113:	andi.	r0,r3,3
+	mtctr	r0
+	beq	120f
+114:	stb	r9,4(r6)
+	addi	r6,r6,1
+	bdnz	114b
+120:	blr
+
 .section __ex_table,"a"
 	.align	2
-	.long	1b,98b
-	.long	11b,98b
-	.long	12b,88b
-	.long	13b,88b
-	.long	14b,3b
-	.long	15b,96b
-	.long	4b,99b
-	.long	16b,81b
-	.long	6b,90b
-	.long	17b,80b
-	.long	77b,76b
-	.long	74b,76b
-	.long	75b,76b
+	.long	70b,100b
+	.long	71b,101b
+	.long	72b,102b
+	.long	73b,103b
+	.long	53b,105b
+	.long	10b,104b
+	.long	11b,104b
+	.long	12b,104b
+	.long	13b,104b
+	.long	14b,105b
+	.long	15b,105b
+	.long	16b,105b
+	.long	17b,105b
+	.long	20b,106b
+	.long	21b,106b
+	.long	22b,106b
+	.long	23b,106b
+	.long	24b,107b
+	.long	25b,107b
+	.long	26b,107b
+	.long	27b,107b
+	.long	30b,108b
+	.long	31b,109b
+	.long	40b,110b
+	.long	41b,111b
+	.long	112b,120b
+	.long	114b,120b
 .text
 
 	.globl	__clear_user
@@ -334,7 +511,6 @@
 	andi.	r0,r6,3
 	add	r4,r0,r4
 	subf	r6,r0,r6
-	/*rlwinm	r0,r4,32-2,2,31*/
 	srwi	r0,r4,2
 	mtctr	r0
 	bdz	6f
diff -urN linux-2.2.17-pre2/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- linux-2.2.17-pre2/arch/ppc/mm/fault.c	Wed May  3 17:16:31 2000
+++ linux/arch/ppc/mm/fault.c	Mon Dec  3 22:05:46 2001
@@ -71,7 +71,10 @@
 	       (error_code&0x80000000)?"I/O ":"",
 	       (regs->trap == 0x400)?"instr":"data"
 	       );*/
-	       
+
+	if (regs->trap == 0x400)
+		error_code &= 0x48200000;
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && regs->trap == 0x300) {
 		debugger_fault_handler(regs);
diff -urN linux-2.2.17-pre2/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- linux-2.2.17-pre2/arch/ppc/mm/init.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/mm/init.c	Mon Dec  3 22:05:46 2001
@@ -416,7 +416,12 @@
 
 void iounmap(void *addr)
 {
-	/* XXX todo */
+	/* For support of dynamic hot swap on the cPCI bus this routine
+	   is now necessary.  This has been well tested on a Motorola
+	   MPC750 (Mesquite) processor board.  Johnnie Peters
+	*/
+	if (addr > high_memory && addr < ioremap_bot)
+		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
 
 unsigned long iopa(unsigned long addr)
diff -urN linux-2.2.17-pre2/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig
--- linux-2.2.17-pre2/arch/ppc/pmac_defconfig	Tue Oct 26 17:53:39 1999
+++ linux/arch/ppc/pmac_defconfig	Mon Dec  3 22:05:46 2001
@@ -253,6 +253,7 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+CONFIG_GMAC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -339,6 +340,7 @@
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
 CONFIG_FB_ATY=y
+CONFIG_FB_ATY128=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
diff -urN linux-2.2.17-pre2/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- linux-2.2.17-pre2/arch/ppc/xmon/start.c	Wed Aug 25 17:29:46 1999
+++ linux/arch/ppc/xmon/start.c	Mon Dec  3 22:05:46 2001
@@ -11,16 +11,30 @@
 #include <asm/prom.h>
 #include <asm/bootx.h>
 #include <asm/pmu.h>
+#include <asm/feature.h>
 
 static volatile unsigned char *sccc, *sccd;
 unsigned long TXRDY, RXRDY;
 extern void xmon_printf(const char *fmt, ...);
-extern void map_bootx_text(void);
 extern void drawchar(char);
 extern void drawstring(const char *str);
+static int xmon_expect(const char *str, unsigned int timeout);
 
 static int console = 0;
 static int use_screen = 0;
+static int via_modem = 0;
+static int xmon_use_sccb = 0;
+static struct device_node *macio_node;
+
+#define TB_SPEED	25000000
+
+static inline unsigned int readtb(void)
+{
+	unsigned int ret;
+
+	asm volatile("mftb %0" : "=r" (ret) :);
+	return ret;
+}
 
 void buf_access(void)
 {
@@ -36,17 +50,18 @@
 	if ( _machine == _MACH_Pmac )
 	{
 		struct device_node *np;
-		extern boot_infos_t *boot_infos;
 		unsigned long addr;
-
 #ifdef CONFIG_BOOTX_TEXT
-		if (boot_infos != 0 && find_via_pmu()) {
+		extern boot_infos_t *disp_bi;
+
+		/* needs to be hacked if xmon_printk is to be used
+ 		   from within find_via_pmu() */
+		if (!via_modem && disp_bi && find_via_pmu()) {
 			printk(KERN_INFO "xmon uses screen and keyboard\n");
 			use_screen = 1;
-			map_bootx_text();
-			return;
 		}
 #endif
+
 #ifdef CHRP_ESCC
 		addr = 0xc1013020;
 #else
@@ -57,18 +72,13 @@
 		
 		np = find_devices("mac-io");
 		if (np && np->n_addrs) {
-			addr = np->addrs[0].address + 0x13000;
-			/* use the B channel on the iMac, A channel on others */
-			if (addr >= 0xf0000000)
-				addr += 0x20; /* use A channel */
+			macio_node = np;
+			addr = np->addrs[0].address + 0x13020;
 		}
-		base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
+		base = (volatile unsigned char *)
+			ioremap(addr & PAGE_MASK, PAGE_SIZE);
 		sccc = base + (addr & ~PAGE_MASK);
-#ifdef CHRP_ESCC
-		sccd = sccc + (0xc1013030 - 0xc1013020);
-#else
-		sccd = sccc + (0xf3013030 - 0xf3013020);
-#endif
+		sccd = sccc + 0x10;
 	}
 	else
 	{
@@ -89,7 +99,7 @@
 xmon_write(void *handle, void *ptr, int nb)
 {
     char *p = ptr;
-    int i, ct;
+    int i, c, ct;
 
 #ifdef CONFIG_BOOTX_TEXT
     if (use_screen) {
@@ -101,19 +111,23 @@
 #endif
     if (!scc_initialized)
 	xmon_init_scc();
+    ct = 0;
     for (i = 0; i < nb; ++i) {
 	while ((*sccc & TXRDY) == 0)
 	    if (adb_hardware == ADB_VIAPMU)
 		pmu_poll();
+	c = p[i];
+	if (c == '\n' && !ct) {
+	    c = '\r';
+	    ct = 1;
+	    --i;
+	} else {
+	    if (console)
+		printk("%c", c);
+	    ct = 0;
+	}
 	buf_access();
-	if ( console && (*p != '\r'))
-		printk("%c", *p);
-	ct = 0;
-	if ( *p == '\n')
-		ct = 1;
-	*sccd = *p++;
-	if ( ct )
-		xmon_write(handle, "\r", 1);
+	*sccd = c;
     }
     return i;
 }
@@ -199,23 +213,30 @@
 	    if (adb_hardware == ADB_VIAPMU)
 		pmu_poll();
 	buf_access();
-#if 0	
-	if ( 0/*console*/ )
-		*p++ = ppc_md.kbd_getkeycode();
-	else
-#endif		
-		*p++ = *sccd;
+	*p++ = *sccd;
     }
     return i;
 }
 
+int
+xmon_read_poll(void)
+{
+	if ((*sccc & RXRDY) == 0) {
+		if (adb_hardware == ADB_VIAPMU)
+			pmu_poll();
+		return -1;
+	}
+	buf_access();
+	return *sccd;
+}
+
 static unsigned char scc_inittab[] = {
     13, 0,		/* set baud rate divisor */
     12, 1,
     14, 1,		/* baud rate gen enable, src=rtxc */
     11, 0x50,		/* clocks = br gen */
-    5,  0x6a,		/* tx 8 bits, assert RTS */
-    4,  0x44,		/* x16 clock, 1 stop */
+    5,  0xea,		/* tx 8 bits, assert DTR & RTS */
+    4,  0x46,		/* x16 clock, 1 stop */
     3,  0xc1,		/* rx enable, 8 bits */
 };
 
@@ -235,6 +256,21 @@
 	{
 		int i, x;
 
+		if (macio_node != 0) {
+			unsigned int t0;
+
+			feature_set(macio_node, FEATURE_Serial_enable);
+			if (via_modem) {
+				feature_set(macio_node, FEATURE_Modem_power);
+				t0 = readtb();
+				while (readtb() - t0 < 3*TB_SPEED)
+					eieio();
+			}
+		}
+		if (xmon_use_sccb) {
+			sccc -= 0x20;
+			sccd -= 0x20;
+		}
 		for (i = 20000; i != 0; --i) {
 			x = *sccc; eieio();
 		}
@@ -246,6 +282,18 @@
 		}
 	}
 	scc_initialized = 1;
+	if (via_modem) {
+		for (;;) {
+			xmon_write(0, "ATE1V1\r", 7);
+			if (xmon_expect("OK", 5)) {
+				xmon_write(0, "ATA\r", 4);
+				if (xmon_expect("CONNECT", 40))
+					break;
+			}
+			xmon_write(0, "+++", 3);
+			xmon_expect("OK", 3);
+		}
+	}
 }
 
 #if 0
@@ -317,6 +365,35 @@
 static char line[256];
 static char *lineptr;
 static int lineleft;
+
+int xmon_expect(const char *str, unsigned int timeout)
+{
+	int c;
+	unsigned int t0;
+
+	timeout *= TB_SPEED;
+	t0 = readtb();
+	do {
+		lineptr = line;
+		for (;;) {
+			c = xmon_read_poll();
+			if (c == -1) {
+				if (readtb() - t0 > timeout) {
+					printk("timeout\n");
+					return 0;
+				}
+				continue;
+			}
+			if (c == '\n')
+				break;
+			printk("%c", c);
+			if (c != '\r' && lineptr < &line[sizeof(line) - 1])
+				*lineptr++ = c;
+		}
+		*lineptr = 0;
+	} while (strstr(line, str) == NULL);
+	return 1;
+}
 
 int
 xmon_getchar(void)
diff -urN linux-2.2.17-pre2/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
--- linux-2.2.17-pre2/arch/sparc64/kernel/psycho.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/sparc64/kernel/psycho.c	Mon Dec  3 22:05:46 2001
@@ -37,6 +37,12 @@
 unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
 unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
 
+/* If this is non-NULL it points to Sabre's DMA write-sync register
+ * which is used by drivers of devices behind bridges other than APB
+ * to synchronize DMA write streams with interrupt delivery.
+ */
+volatile u64 *pci_dma_wsync = NULL;
+
 #ifndef CONFIG_PCI
 
 int pcibios_present(void)
@@ -299,6 +305,8 @@
 		prom_printf("SABRE: Error, cannot map SABRE main registers.\n");
 		prom_halt();
 	}
+
+	pci_dma_wsync = &sabre->psycho_regs->pci_dma_wsync;
 
 	printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
 	       sabre->psycho_regs, sabre->psycho_regs->control);
diff -urN linux-2.2.17-pre2/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.2.17-pre2/arch/sparc64/kernel/sparc64_ksyms.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Dec  3 22:05:46 2001
@@ -43,6 +43,7 @@
 #endif
 #ifdef CONFIG_PCI
 #include <asm/ebus.h>
+#include <asm/pbm.h>
 #endif
 #include <asm/a.out.h>
 #include <asm/svr4.h>
@@ -193,6 +194,7 @@
 EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(pci_dma_wsync);
 #endif
 
 /* Solaris/SunOS binary compatibility */
diff -urN linux-2.2.17-pre2/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- linux-2.2.17-pre2/drivers/block/ide-cd.c	Mon Dec  3 22:05:41 2001
+++ linux/drivers/block/ide-cd.c	Mon Dec  3 22:05:46 2001
@@ -2066,11 +2066,11 @@
 	struct request_sense sense;
 	int ret;
 
-	toc = info->toc;
-	if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL)
+	if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
 		if ((ret = cdrom_read_toc(drive, &sense)))
 			return ret;
 
+	toc = info->toc;
 	ms_info->addr.lba = toc->last_session_lba;
 	ms_info->xa_flag = toc->xa_flag;
 
diff -urN linux-2.2.17-pre2/drivers/char/vt.c linux/drivers/char/vt.c
--- linux-2.2.17-pre2/drivers/char/vt.c	Mon Aug  9 12:04:39 1999
+++ linux/drivers/char/vt.c	Mon Dec  3 22:05:46 2001
@@ -590,6 +590,8 @@
 
 	case KDGETKEYCODE:
 	case KDSETKEYCODE:
+		if(!suser())
+			perm=0;
 		return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
 
 	case KDGKBENT:
diff -urN linux-2.2.17-pre2/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- linux-2.2.17-pre2/drivers/macintosh/adb.c	Wed Aug 25 17:29:48 1999
+++ linux/drivers/macintosh/adb.c	Mon Dec  3 22:05:46 2001
@@ -170,9 +170,9 @@
 	
 	if (adb_controller == NULL)
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
-	else
-	{
+	else {
 		adb_hardware = adb_controller->kind;
+		
 #ifdef CONFIG_PMAC_PBOOK
 		pmu_register_sleep_notifier(&adb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
@@ -194,6 +194,8 @@
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 		adb_got_sleep = 1;
+		if (adb_controller->autopoll)
+			adb_controller->autopoll(0);
 		ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
 		if (ret & NOTIFY_STOP_MASK)
 			return PBOOK_SLEEP_REFUSE;
@@ -209,6 +211,7 @@
 		break;
 	case PBOOK_WAKE:
 		adb_reset_bus();
+		adb_got_sleep = 0;
 		break;
 	}
 	return PBOOK_SLEEP_OK;
@@ -218,15 +221,21 @@
 int
 adb_reset_bus(void)
 {
-	int ret, devs;
+	int ret, nret, devs;
 	unsigned long flags;
 	
 	if (adb_controller == NULL)
 		return -ENXIO;
 		
-	ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
-	if (ret & NOTIFY_STOP_MASK)
+	if (adb_controller->autopoll)
+		adb_controller->autopoll(0);
+
+	nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
+	if (nret & NOTIFY_STOP_MASK) {
+		if (adb_controller->autopoll)
+			adb_controller->autopoll(devs);
 		return -EBUSY;
+	}
 
 	save_flags(flags);
 	cli();
@@ -238,18 +247,17 @@
 	else
 		ret = 0;
 
-	if (!ret)
-	{
+	if (!ret) {
 		devs = adb_scan_bus();
 		if (adb_controller->autopoll)
 			adb_controller->autopoll(devs);
 	}
 
-	ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
-	if (ret & NOTIFY_STOP_MASK)
+	nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+	if (nret & NOTIFY_STOP_MASK)
 		return -EBUSY;
 	
-	return 1;
+	return ret;
 }
 
 void
@@ -327,6 +335,12 @@
 	int i, id;
 	static int dump_adb_input = 0;
 
+	/* We skip keystrokes and mouse moves when the sleep process
+	 * has been started. We stop autopoll, but this is another security
+	 */
+	if (adb_got_sleep)
+		return;
+		
 	id = buf[0] >> 4;
 	if (dump_adb_input) {
 		printk(KERN_INFO "adb packet: ");
@@ -347,12 +361,8 @@
 
 	if (adb_handler[address].handler_id == new_id)
 	    return 1;
-	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-    	    ADB_READREG(address,3));
-	if (req.reply_len < 2)
-	    return 0;
 	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id);	
+	    ADB_WRITEREG(address, 3), address | 0x20, new_id);
 	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
 	    ADB_READREG(address, 3));
 	if (req.reply_len < 2)
@@ -423,7 +433,7 @@
 {
 	struct adbdev_state *state;
 
-	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
+	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL))
 		return -ENXIO;
 	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
 	if (state == 0)
@@ -554,10 +564,11 @@
 	/* Special case for ADB_BUSRESET request, all others are sent to
 	   the controller */
 	if ((req->data[0] == ADB_PACKET)&&(count > 1)
-		&&(req->data[1] == ADB_BUSRESET))
+		&&(req->data[1] == ADB_BUSRESET)) {
 		ret = adb_reset_bus();
-	else
-	{	
+		atomic_dec(&state->n_pending);
+		goto out;
+	} else {	
 		req->reply_expected = ((req->data[1] & 0xc) == 0xc);
 
 		if (adb_controller && adb_controller->send_request)
diff -urN linux-2.2.17-pre2/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- linux-2.2.17-pre2/drivers/macintosh/mac_keyb.c	Wed Aug 25 17:29:48 1999
+++ linux/drivers/macintosh/mac_keyb.c	Mon Dec  3 22:05:46 2001
@@ -24,6 +24,7 @@
  * - 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:
  *
@@ -272,6 +273,7 @@
 #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 int adb_mouse_kinds[16];
 
@@ -490,6 +492,19 @@
     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
+
   */
 	struct kbd_struct *kbd;
 
@@ -521,6 +536,11 @@
 		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;
 	}
 
 	if (adb_mouse_interrupt_hook)
@@ -581,7 +601,7 @@
 	/* Ignore data from register other than 0 */
 	if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
 		return;
-		
+
 	switch (data[1]&0xf )
 	{
 		/* mute */
@@ -645,7 +665,6 @@
 
 static void real_mackbd_leds(unsigned char leds, int device)
 {
-
     if (led_request.complete) {
 	adb_request(&led_request, leds_done, 0, 3,
 		    ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
@@ -705,21 +724,29 @@
 	led_request.complete = 1;
 
 	mackeyb_probe();
-	
+
 	notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier);
 }
 
 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:
-		/* Add unregister_keyboard when merging with Paul Mackerras */
+	    	/* Stop the repeat timer. Autopoll is already off at this point */
+		save_flags(flags);
+		cli();
+		del_timer(&repeat_timer);
+		restore_flags(flags);
+
+		/* Stop pending led requests */
 		while(!led_request.complete)
 			adb_poll();
 		break;
-			
+
 	case ADB_MSG_POST_RESET:
 		mackeyb_probe();
 		break;
@@ -802,7 +829,7 @@
 		    || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
 			init_microspeed(id);
 		} else if (adb_mouse_kinds[id] == ADBMOUSE_MS_A3) {
-			init_ms_a3(id);	
+			init_ms_a3(id);
 		}  else if (adb_mouse_kinds[id] ==  ADBMOUSE_EXTENDED) {
 			/*
 			 * Register 1 is usually used for device
@@ -825,6 +852,14 @@
 			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
 			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
 				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);
+					adb_mouse_kinds[id] = ADBMOUSE_MACALLY2;
+				}
+			}
 		}
 		printk("\n");
         }
@@ -833,7 +868,7 @@
 static void 
 init_trackpad(int id)
 {
-	struct adb_request req;	
+	struct adb_request req;
 	unsigned char r1_buffer[8];
 
 	printk(" (trackpad)");
@@ -886,9 +921,9 @@
 init_trackball(int id)
 {
 	struct adb_request req;
-	
+
 	printk(" (trackman/mouseman)");
-	
+
 	adb_mouse_kinds[id] = ADBMOUSE_TRACKBALL;
 
 	adb_request(&req, NULL, ADBREQ_SYNC, 3,
@@ -924,7 +959,7 @@
         printk(" (TurboMouse 5)");
 
 	adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
-	
+
 	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
 
 	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
diff -urN linux-2.2.17-pre2/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c
--- linux-2.2.17-pre2/drivers/macintosh/macio-adb.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/macio-adb.c	Mon Dec  3 22:05:46 2001
@@ -115,11 +115,6 @@
 	out_8(&adb->intr_enb.r, DFB | TAG);
 
 	adb_controller = &macio_controller;
-//	adb_hardware = ADB_MACIO;
-
-//	adb_send_request = macio_adb_send_request;
-//	adb_autopoll = macio_adb_autopoll;
-//	adb_reset_bus = macio_reset_bus;
 }
 
 static int macio_adb_autopoll(int devs)
diff -urN linux-2.2.17-pre2/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- linux-2.2.17-pre2/drivers/macintosh/macserial.c	Wed May  3 17:16:40 2000
+++ linux/drivers/macintosh/macserial.c	Mon Dec  3 22:05:46 2001
@@ -129,6 +129,22 @@
 
 #define _INLINE_ inline
 
+#ifdef SERIAL_DEBUG_OPEN
+#define OPNDBG(fmt, arg...)	printk(KERN_INFO fmt , ## arg)
+#else
+#define OPNDBG(fmt, arg...)	do { } while (0)
+#endif
+#ifdef SERIAL_DEBUG_POWER
+#define PWRDBG(fmt, arg...)	printk(KERN_INFO fmt , ## arg)
+#else
+#define PWRDBG(fmt, arg...)	do { } while (0)
+#endif
+#ifdef SERIAL_DEBUG_BAUDS
+#define BAUDBG(fmt, arg...)	printk(KERN_INFO fmt , ## arg)
+#else
+#define BAUDBG(fmt, arg...)	do { } while (0)
+#endif
+
 static void probe_sccs(void);
 static void change_speed(struct mac_serial *info, struct termios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -318,7 +334,7 @@
 	 * to it. - paulus)
 	 */
 	for (i = 200; i > 0; --i)
-		if (ld_le32(&dma->control) & RUN)
+		if (ld_le32(&dma->status) & RUN)
 			udelay(1);
 }
 
@@ -398,7 +414,7 @@
 			continue;
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
 			tty_flip_buffer_push(tty);
-			
+
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 			static int flip_buf_ovf;
 			if (++flip_buf_ovf <= 1)
@@ -489,7 +505,7 @@
 			if (info->tx_stopped) {
 #ifdef SERIAL_DEBUG_FLOW
 				printk("CTS up\n");
-#endif			
+#endif
 				info->tx_stopped = 0;
 				if (!info->tx_active)
 					transmit_chars(info);
@@ -497,7 +513,7 @@
 		} else {
 #ifdef SERIAL_DEBUG_FLOW
 			printk("CTS down\n");
-#endif			
+#endif
 			info->tx_stopped = 1;
 		}
 	}
@@ -520,7 +536,7 @@
 	    == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
 		where -= in_le16(&info->rx->res_count);
 	where--;
-	
+
 	stat = read_zsreg(info->zs_channel, R1);
 
 	flag = stat_to_flag(stat);
@@ -566,7 +582,7 @@
 #ifdef SERIAL_DEBUG_INTR
 		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
 		       irq, (int)zs_intreg);
-#endif	
+#endif
 
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
@@ -643,7 +659,7 @@
 
 	if (serial_paranoia_check(info, tty->device, "rs_stop"))
 		return;
-	
+
 #if 0
 	save_flags(flags); cli();
 	if (info->curregs[5] & TxENAB) {
@@ -659,7 +675,7 @@
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
-	
+
 #ifdef SERIAL_DEBUG_STOP
 	printk("rs_start %ld....\n", 
 	       tty->ldisc.chars_in_buffer(tty));
@@ -667,7 +683,7 @@
 
 	if (serial_paranoia_check(info, tty->device, "rs_start"))
 		return;
-	
+
 	save_flags(flags); cli();
 #if 0
 	if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
@@ -701,7 +717,7 @@
 {
 	struct mac_serial	*info = (struct mac_serial *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -719,14 +735,10 @@
 {
 	int delay;
 
-#ifdef SERIAL_DEBUG_OPEN
-	printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
-#endif
+	OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
  
 	if (info->flags & ZILOG_INITIALIZED) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk(" -> already inited\n");
-#endif
+		OPNDBG(" -> already inited\n");
  		return 0;
 	}
 
@@ -736,22 +748,17 @@
 			return -ENOMEM;
 	}
 
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
+	OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
 
 	delay = set_scc_power(info, 1);
-	
+
 	setup_scc(info);
 
-#ifdef SERIAL_DEBUG_OPEN
-	printk("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-#endif
+	OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
 
 	info->flags |= ZILOG_INITIALIZED;
 	enable_irq(info->irq);
 	if (info->dma_initted) {
-//		enable_irq(info->tx_dma_irq);
 		enable_irq(info->rx_dma_irq);
 	}
 
@@ -874,8 +881,6 @@
 	volatile struct dbdma_cmd *cd;
 	unsigned char *p;
 
-//printk(KERN_DEBUG "SCC: dma_init\n");
-
 	info->rx_nbuf = 8;
 
 	/* various mem set up */
@@ -951,12 +956,10 @@
 static int setup_scc(struct mac_serial * info)
 {
 	unsigned long flags;
-	
-#ifdef SERIAL_DEBUG_OPEN
-	printk("setting up ttys%d SCC...\n", info->line);
-#endif
 
-	save_flags(flags); cli(); /* Disable interrupts */	
+	OPNDBG("setting up ttys%d SCC...\n", info->line);
+
+	save_flags(flags); cli(); /* Disable interrupts */
 
 	/*
 	 * Reset the chip.
@@ -987,7 +990,8 @@
 	/*
 	 * Turn on RTS and DTR.
 	 */
-	zs_rtsdtr(info, 1);
+	if (!info->is_irda)
+		zs_rtsdtr(info, 1);
 
 	/*
 	 * Finally, enable sequencing and interrupts
@@ -1051,16 +1055,11 @@
  */
 static void shutdown(struct mac_serial * info)
 {
-#ifdef SERIAL_DEBUG_OPEN
-	printk("Shutting down serial port %d (irq %d)....\n", info->line,
+	OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
 	       info->irq);
-#endif
-	
+
 	if (!(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("(already shutdown)\n");
-#endif
-	
+		OPNDBG("(already shutdown)\n");
 		return;
 	}
 
@@ -1124,86 +1123,63 @@
 	/* The timings looks strange but that's the ones MacOS seems
 	   to use for the internal modem. I think we can use a lot faster
 	   ones, at least whe not using the modem, this should be tested.
-	 */				
+	 */
 	if (state) {
-#ifdef SERIAL_DEBUG_POWER
-		printk(KERN_INFO "ttyS%02d: powering up hardware\n", info->line);
-#endif
+		PWRDBG("ttyS%02d: powering up hardware\n", info->line);
 		if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) {
-			feature_clear(info->dev_node, FEATURE_Serial_reset);
-			mdelay(5);
 			feature_set(info->dev_node, FEATURE_Serial_enable);
+			mdelay(10);
+			feature_set(info->dev_node, FEATURE_Serial_reset);
+			mdelay(15);
+			feature_clear(info->dev_node, FEATURE_Serial_reset);
+			mdelay(10);
 		}
 		if (info->zs_chan_a == info->zs_channel)
 			feature_set(info->dev_node, FEATURE_Serial_IO_A);
 		else
 			feature_set(info->dev_node, FEATURE_Serial_IO_B);
-		delay = 1;
-		
+		delay = 10;
 		if (info->is_cobalt_modem){
-			feature_set(info->dev_node, FEATURE_Modem_Reset);
+			mdelay(300);
+			feature_set(info->dev_node, FEATURE_Modem_power);
 	   		mdelay(5);
-			feature_clear(info->dev_node, FEATURE_Modem_Reset);
+			feature_clear(info->dev_node, FEATURE_Modem_power);
+	   		mdelay(10);
+			feature_set(info->dev_node, FEATURE_Modem_power);
 			delay = 2500;	/* wait for 2.5s before using */
 		}
 #ifdef CONFIG_PMAC_PBOOK
-		if (info->is_pwbk_ir)
+		if (info->is_irda)
 			pmu_enable_irled(1);
 #endif /* CONFIG_PMAC_PBOOK */
 	} else {
-#ifdef SERIAL_DEBUG_POWER
-		printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line);
-#endif
-#ifdef CONFIG_KGDB
-		if (info->kgdb_channel) {
-#ifdef SERIAL_DEBUG_POWER
-			printk(KERN_INFO "        (canceled by KGDB)\n");
-#endif
-			return 0;
-		}
-#endif
-#ifdef CONFIG_XMON
-		if (!info->is_cobalt_modem) {
-#ifdef SERIAL_DEBUG_POWER
-			printk(KERN_INFO "        (canceled by XMON)\n");
-#endif
-			return 0;
-		}
-#endif
+		PWRDBG("ttyS%02d: shutting down hardware\n", info->line);
 		if (info->is_cobalt_modem) {
-#ifdef SERIAL_DEBUG_POWER
-			printk(KERN_INFO "ttyS%02d: shutting down modem\n", info->line);
-#endif
-			feature_set(info->dev_node, FEATURE_Modem_Reset);
-			mdelay(15);
-			feature_clear(info->dev_node, FEATURE_Modem_Reset);
-			mdelay(25);
+			PWRDBG("ttyS%02d: shutting down modem\n", info->line);
+			feature_clear(info->dev_node, FEATURE_Modem_power);
+			mdelay(10);
 		}
 #ifdef CONFIG_PMAC_PBOOK
-		if (info->is_pwbk_ir)
+		if (info->is_irda)
 			pmu_enable_irled(0);
 #endif /* CONFIG_PMAC_PBOOK */
-			
-		if (info->zs_chan_a == info->zs_channel) {
-#ifdef SERIAL_DEBUG_POWER
-			printk(KERN_INFO "ttyS%02d: shutting down SCC channel A\n", info->line);
-#endif
+
+		if (info->zs_chan_a == info->zs_channel && !info->is_irda) {
+			PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line);
 			feature_clear(info->dev_node, FEATURE_Serial_IO_A);
-		} else {
-#ifdef SERIAL_DEBUG_POWER
-			printk(KERN_INFO "ttyS%02d: shutting down SCC channel B\n", info->line);
-#endif
+		} else if (!info->is_irda) {
+			PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line);
 			feature_clear(info->dev_node, FEATURE_Serial_IO_B);
 		}
 		/* XXX for now, shut down SCC core only on powerbooks */
 		if (is_powerbook
 		    && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) ||
 			 feature_test(info->dev_node, FEATURE_Serial_IO_B))) {
-#ifdef SERIAL_DEBUG_POWER
-			printk(KERN_INFO "ttyS%02d: shutting down SCC core\n", info->line);
-#endif
+			PWRDBG("ttyS%02d: shutting down SCC core\n", info->line);
 			feature_set(info->dev_node, FEATURE_Serial_reset);
-			mdelay(10);
+			mdelay(15);
+			feature_clear(info->dev_node, FEATURE_Serial_reset);
+			mdelay(25);
 			feature_clear(info->dev_node, FEATURE_Serial_enable);
 			mdelay(5);
 		}
@@ -1211,6 +1187,113 @@
 	return delay;
 }
 
+static void irda_rts_pulses(struct mac_serial *info, int w)
+{
+	unsigned long flags;
+
+	udelay(w);
+	save_flags(flags); cli();
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
+	udelay(2);
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+	udelay(8);
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
+	udelay(4);
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+	restore_flags(flags);
+}
+
+/*
+ * Set the irda codec on the imac to the specified baud rate.
+ */
+static void irda_setup(struct mac_serial *info)
+{
+	int code, speed, t;
+	unsigned long flags;
+
+	speed = info->tty->termios->c_cflag & CBAUD;
+	if (speed < B2400 || speed > B115200)
+		return;
+	code = 0x4d + B115200 - speed;
+
+	/* disable serial interrupts and receive DMA */
+	write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
+
+	/* wait for transmitter to drain */
+	t = 10000;
+	while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
+	       || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+		if (--t <= 0) {
+			printk(KERN_ERR "transmitter didn't drain\n");
+			return;
+		}
+		udelay(10);
+	}
+	udelay(100);
+
+	/* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
+	write_zsreg(info->zs_channel, 4, X16CLK | SB1);
+	write_zsreg(info->zs_channel, 11, TCBR | RCBR);
+	t = BPS_TO_BRG(19200, ZS_CLOCK/16);
+	write_zsreg(info->zs_channel, 12, t);
+	write_zsreg(info->zs_channel, 13, t >> 8);
+	write_zsreg(info->zs_channel, 14, BRENABL);
+	write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+
+	/* set TxD low for ~104us and pulse RTS */
+	udelay(1000);
+	save_flags(flags); cli();
+	write_zsdata(info->zs_channel, 0xfe);
+	irda_rts_pulses(info, 150);
+	restore_flags(flags);
+	irda_rts_pulses(info, 180);
+	irda_rts_pulses(info, 50);
+	udelay(100);
+
+	/* assert DTR, wait 30ms, talk to the chip */
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
+	udelay(30000);
+	while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
+		read_zsdata(info->zs_channel);
+
+	write_zsdata(info->zs_channel, 1);
+	t = 1000;
+	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
+		if (--t <= 0) {
+			printk(KERN_ERR "irda_setup timed out on 1st byte\n");
+			goto out;
+		}
+		udelay(10);
+	}
+	t = read_zsdata(info->zs_channel);
+	if (t != 4)
+		printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
+
+	write_zsdata(info->zs_channel, code);
+	t = 1000;
+	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
+		if (--t <= 0) {
+			printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
+			goto out;
+		}
+		udelay(10);
+	}
+	t = read_zsdata(info->zs_channel);
+	if (t != code)
+		printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
+
+	/* Drop DTR again and do some more RTS pulses */
+ out:
+	udelay(100);
+	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
+	irda_rts_pulses(info, 80);
+
+	/* We should be right to go now.  We assume that load_zsregs
+	   will get called soon to load up the correct baud rate etc. */
+	info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
+	info->pendregs[5] = info->curregs[5];
+}
 
 /*
  * This routine is called to set the UART divisor registers to match
@@ -1218,7 +1301,6 @@
  */
 static void change_speed(struct mac_serial *info, struct termios *old_termios)
 {
-	unsigned short port;
 	unsigned cflag;
 	int	bits;
 	int	brg, baud;
@@ -1226,8 +1308,6 @@
 
 	if (!info->tty || !info->tty->termios)
 		return;
-	if (!(port = info->port))
-		return;
 
 	cflag = info->tty->termios->c_cflag;
 	baud = tty_get_baud_rate(info->tty);
@@ -1250,9 +1330,7 @@
 	info->zs_baud = baud;
 	info->clk_divisor = 16;
 
-#ifdef SERIAL_DEBUG_BAUDS
-	printk("set speed to %d bds, ", baud);
-#endif
+	BAUDBG("set speed to %d bds, ", baud);
 
 	switch (baud) {
 	case ZS_CLOCK/16:	/* 230400 */
@@ -1279,34 +1357,26 @@
 	case CS5:
 		info->curregs[3] |= Rx5;
 		info->curregs[5] |= Tx5;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("5 bits, ");
-#endif
+		BAUDBG("5 bits, ");
 		bits = 7;
 		break;
 	case CS6:
 		info->curregs[3] |= Rx6;
 		info->curregs[5] |= Tx6;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("6 bits, ");
-#endif
+		BAUDBG("6 bits, ");
 		bits = 8;
 		break;
 	case CS7:
 		info->curregs[3] |= Rx7;
 		info->curregs[5] |= Tx7;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("7 bits, ");
-#endif
+		BAUDBG("7 bits, ");
 		bits = 9;
 		break;
 	case CS8:
 	default: /* defaults to 8 bits */
 		info->curregs[3] |= Rx8;
 		info->curregs[5] |= Tx8;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("8 bits, ");
-#endif
+		BAUDBG("8 bits, ");
 		bits = 10;
 		break;
 	}
@@ -1317,21 +1387,15 @@
 	if (cflag & CSTOPB) {
 		info->curregs[4] |= SB2;
 		bits++;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("2 stop, ");
-#endif
+		BAUDBG("2 stop, ");
 	} else {
 		info->curregs[4] |= SB1;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("1 stop, ");
-#endif
+		BAUDBG("1 stop, ");
 	}
 	if (cflag & PARENB) {
 		bits++;
  		info->curregs[4] |= PAR_ENA;
-#ifdef SERIAL_DEBUG_BAUDS
-		printk("parity, ");
-#endif
+		BAUDBG("parity, ");
 	}
 	if (!(cflag & PARODD)) {
 		info->curregs[4] |= PAR_EVEN;
@@ -1361,9 +1425,12 @@
 	info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
 	info->timeout += HZ/50+1;	/* Add .02 seconds of slop */
 
-#ifdef SERIAL_DEBUG_BAUDS
-	printk("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ, (int)info->baud_base);
-#endif
+	BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
+	       (int)info->baud_base);
+
+	/* set the irda codec to the right rate */
+	if (info->is_irda)
+		irda_setup(info);
 
 	/* Load up the new values */
 	load_zsregs(info->zs_channel, info->curregs);
@@ -1431,7 +1498,7 @@
 	} else {
 		while (1) {
 			save_flags(flags);
-			cli();		
+			cli();
 			c = MIN(count,
 				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				    SERIAL_XMIT_SIZE - info->xmit_head));
@@ -1459,7 +1526,7 @@
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	int	ret;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
 		return 0;
 	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -1471,7 +1538,7 @@
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
 		return 0;
 	return info->xmit_cnt;
@@ -1481,7 +1548,7 @@
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
 	save_flags(flags); cli();
@@ -1507,13 +1574,13 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	
+
 	printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		save_flags(flags); cli();
 		info->x_char = STOP_CHAR(tty);
@@ -1543,13 +1610,13 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	
+
 	printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		save_flags(flags); cli();
 		if (info->x_char)
@@ -1726,8 +1793,6 @@
 
 	if (serial_paranoia_check(info, tty->device, "rs_break"))
 		return;
-	if (!info->port)
-		return;
 
 	save_flags(flags); cli();
 	if (break_state == -1)
@@ -1755,7 +1820,7 @@
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
-	
+
 	switch (cmd) {
 		case TIOCMGET:
 			return get_modem_info(info, (unsigned int *) arg);
@@ -1777,7 +1842,7 @@
 					 info, sizeof(struct mac_serial)))
 				return -EFAULT;
 			return 0;
-			
+
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -1816,18 +1881,16 @@
 
 	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
 		return;
-	
+
 	save_flags(flags); cli();
-	
+
 	if (tty_hung_up_p(filp)) {
 		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
-	
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
-#endif
+
+	OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count);
 	if ((tty->count == 1) && (info->count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
@@ -1863,9 +1926,7 @@
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
 	 */
-#ifdef SERIAL_DEBUG_OPEN
-	printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
-#endif
+	OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
 	tty->closing = 1;
 	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
 		restore_flags(flags);
@@ -1889,9 +1950,7 @@
 		 * Before we drop DTR, make sure the SCC transmitter
 		 * has completely drained.
 		 */
-#ifdef SERIAL_DEBUG_OPEN
-		printk("waiting end of Rx...\n");
-#endif
+		OPNDBG("waiting end of Rx...\n");
 		restore_flags(flags);
 		rs_wait_until_sent(tty, info->timeout);
 		save_flags(flags); cli();
@@ -2031,7 +2090,7 @@
 		info->flags |= ZILOG_CALLOUT_ACTIVE;
 		return 0;
 	}
-	
+
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
@@ -2051,7 +2110,7 @@
 		if (tty->termios->c_cflag & CLOCAL)
 			do_clocal = 1;
 	}
-	
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -2061,10 +2120,8 @@
 	 */
 	retval = 0;
 	add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttys%d, count = %d\n",
+	OPNDBG("block_til_ready before block: ttys%d, count = %d\n",
 	       info->line, info->count);
-#endif
 	cli();
 	if (!tty_hung_up_p(filp)) 
 		info->count--;
@@ -2073,7 +2130,8 @@
 	while (1) {
 		cli();
 		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		    (tty->termios->c_cflag & CBAUD) &&
+		    !info->is_irda)
 			zs_rtsdtr(info, 1);
 		sti();
 		current->state = TASK_INTERRUPTIBLE;
@@ -2083,7 +2141,7 @@
 			if (info->flags & ZILOG_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
-				retval = -ERESTARTSYS;	
+				retval = -ERESTARTSYS;
 #else
 			retval = -EAGAIN;
 #endif
@@ -2097,10 +2155,8 @@
 			retval = -ERESTARTSYS;
 			break;
 		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		OPNDBG("block_til_ready blocking: ttys%d, count = %d\n",
 		       info->line, info->count);
-#endif
 		schedule();
 	}
 	current->state = TASK_RUNNING;
@@ -2108,15 +2164,13 @@
 	if (!tty_hung_up_p(filp))
 		info->count++;
 	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n",
 	       info->line, info->count);
-#endif
 	if (retval)
 		return retval;
 	info->flags |= ZILOG_NORMAL_ACTIVE;
 	return 0;
-}	
+}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -2146,10 +2200,8 @@
 #endif
 	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	OPNDBG("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
 	       info->count);
-#endif
 
 	info->count++;
 	tty->driver_data = info;
@@ -2190,10 +2242,8 @@
 
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("rs_open returning after block_til_ready with %d\n",
+		OPNDBG("rs_open returning after block_til_ready with %d\n",
 			retval);
-#endif
 		return retval;
 	}
 
@@ -2215,9 +2265,7 @@
 	info->session = current->session;
 	info->pgrp = current->pgrp;
 
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open ttys%d successful...\n", info->line);
-#endif
+	OPNDBG("rs_open ttys%d successful...\n", info->line);
 	return 0;
 }
 
@@ -2239,6 +2287,10 @@
 	struct device_node *ch = zss->dev_node;
 	char *conn;
 	int len;
+	struct slot_names_prop {
+		int	count;
+		char	name[1];
+	} *slots;
 
 	zss->irq = ch->intrs[0].line;
 	zss->has_dma = 0;
@@ -2263,7 +2315,11 @@
 	/* XXX tested only with wallstreet PowerBook,
 	   should do no harm anyway */
 	conn = get_property(ch, "AAPL,connector", &len);
-	zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+	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 (zss->has_dma) {
 		zss->dma_priv = NULL;
@@ -2453,7 +2509,7 @@
 		zs_soft[channel].clk_divisor = 16;
 /* -- we are not sure the SCC is powered ON at this point
  		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/		
+*/
 		zs_soft[channel].zs_baud = 38400;
 
 		/* If console serial line, then enable interrupts. */
@@ -2504,20 +2560,17 @@
 			printk(", port = %s", connector);
 		if (info->is_cobalt_modem)
 			printk(" (cobalt modem)");
-		if (info->is_pwbk_ir)
-			printk(" (powerbook IR)");
+		if (info->is_irda)
+			printk(" (IrDA)");
 		printk("\n");
 
+#ifndef CONFIG_XMON
 #ifdef CONFIG_KGDB
-		if (info->kgdb_channel)
-			continue;
-#endif			
-#ifdef CONFIG_XMON
-		if (!info->is_cobalt_modem)
-			continue;
-#endif			
-		/* By default, disable the port */
-		set_scc_power(info, 0);
+		if (!info->kgdb_channel)
+#endif /* CONFIG_KGDB */
+			/* By default, disable the port */
+			set_scc_power(info, 0);
+#endif /* CONFIG_XMON */
  	}
 	tmp_buf = 0;
 
@@ -2613,7 +2666,7 @@
 			while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
                                 == 0)
 				eieio();
-			
+
 			write_zsdata(info->zs_channel, 13);
 		}
 	}
@@ -2922,7 +2975,7 @@
 		probe_sccs();
 
 	set_scc_power(&zs_soft[tty_num], 1);
-	
+
 	zs_kgdbchan = zs_soft[tty_num].zs_channel;
 	zs_soft[tty_num].change_needed = 0;
 	zs_soft[tty_num].clk_divisor = 16;
@@ -2944,12 +2997,12 @@
 serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
 	int i;
-	
+
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 	case PBOOK_SLEEP_REJECT:
 		break;
-		
+
 	case PBOOK_SLEEP_NOW:
 		for (i=0; i<zs_channels_found; i++) {
 			struct mac_serial *info = &zs_soft[i];
diff -urN linux-2.2.17-pre2/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- linux-2.2.17-pre2/drivers/macintosh/macserial.h	Tue Jan  4 10:12:17 2000
+++ linux/drivers/macintosh/macserial.h	Mon Dec  3 22:05:46 2001
@@ -111,7 +111,7 @@
 	char kgdb_channel;  /* Kgdb is running on this channel */
 	char is_cons;       /* Is this our console. */
 	char is_cobalt_modem;	/* is a gatwick-based cobalt modem */
-	char is_pwbk_ir;	/* is connected to an IR led on powerbooks */
+	char is_irda;		/* is connected to an IrDA codec */
 	unsigned char tx_active; /* character is being xmitted */
 	unsigned char tx_stopped; /* output is suspended */
 
diff -urN linux-2.2.17-pre2/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- linux-2.2.17-pre2/drivers/macintosh/mediabay.c	Tue Jan  4 10:12:17 2000
+++ linux/drivers/macintosh/mediabay.c	Mon Dec  3 22:05:46 2001
@@ -3,6 +3,8 @@
  *
  * Copyright (C) 1998 Paul Mackerras.
  *
+ * Various evolutions by Benjamin Herrenschmidt & Henry Worth
+ *
  *  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
@@ -38,6 +40,14 @@
 #endif
 
 #undef MB_USE_INTERRUPTS
+#undef MB_DEBUG
+#define MB_IGNORE_SIGNALS
+
+#ifdef MB_DEBUG
+#define MBDBG(fmt, arg...)	printk(KERN_INFO fmt , ## arg)
+#else
+#define MBDBG(fmt, arg...)	do { } while (0)
+#endif
 
 struct media_bay_hw {
 	unsigned char	b0;
@@ -48,18 +58,20 @@
 
 struct media_bay_info {
 	volatile struct media_bay_hw*	addr;
+	volatile u8*			extint_gpio;
 	int				content_id;
-	int				previous_id;
-	int				ready;
+	int				state;
 	int				last_value;
 	int				value_count;
-	int				reset_timer;
+	int				timer;
 	struct device_node*		dev_node;
+	int				pismo;	/* New PowerBook3,1 */
+	int				gpio_cache;
 #ifdef CONFIG_BLK_DEV_IDE
 	unsigned long			cd_base;
 	int 				cd_index;
 	int				cd_irq;
-	int				cd_timer;
+	int				cd_retry;
 #endif
 };
 
@@ -68,42 +80,102 @@
 static volatile struct media_bay_info media_bays[MAX_BAYS];
 int media_bay_count = 0;
 
-#define MB_CONTENTS(i)	((in_8(&media_bays[i].addr->contents) >> 4) & 7)
+inline int mb_content(volatile struct media_bay_info *bay)
+{
+        if (bay->pismo) {
+                unsigned char new_gpio = in_8(bay->extint_gpio + 0xe) & 2;
+                if (new_gpio) {
+                	bay->gpio_cache = new_gpio;
+                        return MB_NO;
+                } else if (bay->gpio_cache != new_gpio) {
+                        /* make sure content bits are set */
+                        feature_set(bay->dev_node, FEATURE_Mediabay_content);
+                        udelay(5);
+                        bay->gpio_cache = new_gpio;
+                }
+                return (in_le32((unsigned*)bay->addr) >> 4) & 0xf;
+        } else {
+                int cont = (in_8(&bay->addr->contents) >> 4) & 7;
+                return (cont == 7) ? MB_NO : cont;
+        }
+}
 
 #ifdef CONFIG_BLK_DEV_IDE
 /* check the busy bit in the media-bay ide interface
    (assumes the media-bay contains an ide device) */
+//#define MB_IDE_READY(i)	((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40)
 #define MB_IDE_READY(i)	((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
 #endif
 
+/* Note: All delays are not in milliseconds and converted to HZ relative
+ * values by the macro below
+ */
+#define MS_TO_HZ(ms)	((ms * HZ) / 1000)
+
 /*
  * Consider the media-bay ID value stable if it is the same for
- * this many consecutive samples (at intervals of 1/HZ seconds).
+ * this number of milliseconds
+ */
+#define MB_STABLE_DELAY	40
+
+/* Wait after powering up the media bay this delay in ms
+ * timeout bumped for some powerbooks
  */
-#define MB_STABLE_COUNT	4
+#define MB_POWER_DELAY	200
 
 /*
  * Hold the media-bay reset signal true for this many ticks
  * after a device is inserted before releasing it.
  */
-#define MB_RESET_COUNT	40
+#define MB_RESET_DELAY	40
+
+/*
+ * Wait this long after the reset signal is released and before doing
+ * further operations. After this delay, the IDE reset signal is released
+ * too for an IDE device
+ */
+#define MB_SETUP_DELAY	100
 
 /*
  * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
- * (or until the device is ready) before registering the IDE interface.
+ * (or until the device is ready) before waiting for busy bit to disappear
+ */
+#define MB_IDE_WAIT	1000
+
+/*
+ * Timeout waiting for busy bit of an IDE device to go down
  */
-#define MB_IDE_WAIT	1500
+#define MB_IDE_TIMEOUT	5000
 
 /*
- * Wait at least this many ticks after resetting an IDE device before
- * believing its ready bit.
+ * Max retries of the full power up/down sequence for an IDE device
  */
-#define MB_IDE_MINWAIT	250
+#define MAX_CD_RETRIES	3
+
+/*
+ * States of a media bay
+ */
+enum {
+	mb_empty = 0,		/* Idle */
+	mb_powering_up,		/* power bit set, waiting MB_POWER_DELAY */
+	mb_enabling_bay,	/* enable bits set, waiting MB_RESET_DELAY */
+	mb_resetting,		/* reset bit unset, waiting MB_SETUP_DELAY */
+	mb_ide_resetting,	/* IDE reset bit unser, waiting MB_IDE_WAIT */
+	mb_ide_waiting,		/* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */
+	mb_up,			/* Media bay full */
+	mb_powering_down	/* Powering down (avoid too fast down/up) */
+};
 
 static void poll_media_bay(int which);
 static void set_media_bay(int which, int id);
+static void set_mb_power(int which, int onoff);
+static void media_bay_step(int i);
 static int media_bay_task(void *);
 
+#ifdef MB_USE_INTERRUPTS
+static void media_bay_intr(int irq, void *devid, struct pt_regs *regs);
+#endif
+
 /*
  * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
  * register is always set when there is something in the media bay.
@@ -120,56 +192,69 @@
 {
 	struct device_node *np;
 	int		n,i;
-	
-	for (i=0; i<MAX_BAYS; i++)
-	{
+
+	for (i=0; i<MAX_BAYS; i++) {
 		memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
 		media_bays[i].content_id	= -1;
 #ifdef CONFIG_BLK_DEV_IDE
 		media_bays[i].cd_index		= -1;
 #endif
 	}
-	
+
 	np = find_devices("media-bay");
 	n = 0;
-	while(np && (n<MAX_BAYS))
-	{
+	while(np && (n<MAX_BAYS)) {
 		if (np->n_addrs == 0)
 			continue;
 		media_bays[n].addr = (volatile struct media_bay_hw *)
 			ioremap(np->addrs[0].address, sizeof(struct media_bay_hw));
 
+		media_bays[n].pismo = device_is_compatible(np, "keylargo-media-bay");
+		if (media_bays[n].pismo) {
+			if (!np->parent || strcmp(np->parent->name, "mac-io")) {
+				printk(KERN_ERR "Pismo media-bay has no mac-io parent !\n");
+				continue;
+			}
+			media_bays[n].extint_gpio = ioremap(np->parent->addrs[0].address
+				+ 0x58, 0x10);
+		}
+
 #ifdef MB_USE_INTERRUPTS
-		if (np->n_intrs == 0)
-		{
+		if (np->n_intrs == 0) {
 			printk(KERN_ERR "media bay %d has no irq\n",n);
 			continue;
 		}
-		
-		if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL))
-		{
-			printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n);
+
+		if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) {
+			printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n",
+				np->intrs[0].line, n);
 			continue;
 		}
-#endif	
+#endif
 		media_bay_count++;
-	
-		set_media_bay(n, MB_CONTENTS(n));
-		if (media_bays[n].content_id != MB_NO) {
-			feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset);
-			udelay(500);
-		}
-		media_bays[n].ready		= 1;
-		media_bays[n].previous_id	= media_bays[n].content_id;
-		media_bays[n].reset_timer	= 0;
+
 		media_bays[n].dev_node		= np;
-#ifdef CONFIG_BLK_DEV_IDE
-		media_bays[n].cd_timer		= 0;
-#endif
+
+		/* Force an immediate detect */
+		set_mb_power(n,0);
+		mdelay(MB_POWER_DELAY);
+		if(!media_bays[n].pismo)
+			out_8(&media_bays[n].addr->contents, 0x70);
+		mdelay(MB_STABLE_DELAY);
+		media_bays[n].content_id = MB_NO;
+		media_bays[n].last_value = mb_content(&media_bays[n]);
+		media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY);
+		media_bays[n].state = mb_empty;
+		do {
+			mdelay(1000/HZ);
+			media_bay_step(n);
+		} while((media_bays[n].state != mb_empty) &&
+			(media_bays[n].state != mb_up));
+
 		n++;
 		np=np->next;
 	}
-	
+
 	if (media_bay_count)
 	{
 		printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
@@ -178,21 +263,83 @@
 		pmu_register_sleep_notifier(&mb_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
-		kernel_thread(media_bay_task, NULL, 0);
+		kernel_thread(media_bay_task, NULL,
+			      CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	}
 }
 
-#if 0
+#ifdef MB_USE_INTERRUPTS
 static void
 media_bay_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	int id = MB_CONTENTS();
-
-	if (id == MB_NO)
-		set_media_bay(id);
 }
 #endif
 
+static void
+set_mb_power(int which, int onoff)
+{
+	volatile struct media_bay_info*	mb = &media_bays[which];
+
+	if (onoff) {
+		feature_set(mb->dev_node, FEATURE_Mediabay_power);
+		udelay(10);
+		feature_set(mb->dev_node, FEATURE_Mediabay_reset);
+		udelay(10);
+		mb->state = mb_powering_up;
+		MBDBG("mediabay%d: powering up\n", which);
+	} else {
+		feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable);
+		if (mb->pismo)
+			feature_clear(mb->dev_node, FEATURE_IDE0_enable);
+		else
+			feature_clear(mb->dev_node, FEATURE_IDE1_enable);
+		feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_switch);
+		feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable);
+		feature_clear(mb->dev_node, FEATURE_SWIM3_enable);
+		feature_clear(mb->dev_node, FEATURE_Mediabay_power);
+		mb->state = mb_powering_down;
+		MBDBG("mediabay%d: powering down\n", which);
+	}
+	mb->timer = MS_TO_HZ(MB_POWER_DELAY);
+}
+
+static void
+set_media_bay(int which, int id)
+{
+	volatile struct media_bay_info* bay;
+
+	bay = &media_bays[which];
+
+	switch (id) {
+	case MB_CD:
+		if (bay->pismo) {
+			feature_set(bay->dev_node, FEATURE_Mediabay_IDE_switch);
+			udelay(10);
+			feature_set(bay->dev_node, FEATURE_IDE0_enable);
+			udelay(10);
+			feature_set(bay->dev_node, FEATURE_IDE0_reset);
+		} else {
+			feature_set(bay->dev_node, FEATURE_IDE1_enable);
+			udelay(10);
+			feature_set(bay->dev_node, FEATURE_IDE1_reset);
+		}
+		printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
+		break;
+	case MB_FD:
+	case MB_FD1:
+		feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+		feature_set(bay->dev_node, FEATURE_SWIM3_enable);
+		printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
+		break;
+	case MB_NO:
+		break;
+	default:
+		printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
+		       which, id);
+		break;
+	}
+}
+
 int
 check_media_bay(struct device_node *which_bay, int what)
 {
@@ -202,7 +349,7 @@
 	for (i=0; i<media_bay_count; i++)
 		if (which_bay == media_bays[i].dev_node)
 		{
-			if ((what == media_bays[i].content_id) && media_bays[i].ready)
+			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
 				return 0;
 			media_bays[i].cd_index = -1;
 			return -EINVAL;
@@ -220,13 +367,13 @@
 	for (i=0; i<media_bay_count; i++)
 		if (base == media_bays[i].cd_base)
 		{
-			if ((what == media_bays[i].content_id) && media_bays[i].ready)
+			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
 				return 0;
 			media_bays[i].cd_index = -1;
 			return -EINVAL;
 		} 
 #endif
-	
+
 	return -ENODEV;
 }
 
@@ -240,17 +387,138 @@
 	for (i=0; i<media_bay_count; i++)
 		if (which_bay == media_bays[i].dev_node)
 		{
+			int timeout = 5000;
+
  			media_bays[i].cd_base	= base;
 			media_bays[i].cd_irq	= irq;
-			media_bays[i].cd_index	= index;
-			printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);			
-			return 0;
+
+			if ((MB_CD != media_bays[i].content_id) || media_bays[i].state != mb_up)
+				return 0;
+
+			printk(KERN_DEBUG "Registered ide %d for media bay %d\n", index, i);
+			do {
+				if (MB_IDE_READY(i)) {
+					media_bays[i].cd_index	= index;
+					return 0;
+				}
+				mdelay(1);
+			} while(--timeout);
+			printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i);
+			return -ENODEV;
 		} 
 #endif
-	
+
 	return -ENODEV;
 }
 
+static void
+media_bay_step(int i)
+{
+	volatile struct media_bay_info* bay = &media_bays[i];
+
+	/* We don't poll when powering down */
+	if (bay->state != mb_powering_down)
+	    poll_media_bay(i);
+
+	/* If timer expired or polling IDE busy, run state machine */
+	if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0))
+	    return;
+
+	switch(bay->state) {
+	case mb_powering_up:
+	    	set_media_bay(i, bay->last_value);
+	    	bay->timer = MS_TO_HZ(MB_RESET_DELAY);
+	    	bay->state = mb_enabling_bay;
+		MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);
+		break;
+	case mb_enabling_bay:
+	    	feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+	    	bay->timer = MS_TO_HZ(MB_SETUP_DELAY);
+	    	bay->state = mb_resetting;
+		MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
+	    	break;
+	    
+	case mb_resetting:
+		if (bay->content_id != MB_CD) {
+			MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
+			bay->state = mb_up;
+			break;
+	    	}
+#ifdef CONFIG_BLK_DEV_IDE
+		MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
+		if (bay->pismo)
+	    		feature_clear(bay->dev_node, FEATURE_IDE0_reset);
+		else
+	    		feature_clear(bay->dev_node, FEATURE_IDE1_reset);
+	    	bay->timer = MS_TO_HZ(MB_IDE_WAIT);
+	    	bay->state = mb_ide_resetting;
+#else
+		printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
+		set_mb_power(i, 0);
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+	    	break;
+	    
+#ifdef CONFIG_BLK_DEV_IDE
+	case mb_ide_resetting:
+	    	bay->timer = MS_TO_HZ(MB_IDE_TIMEOUT);
+	    	bay->state = mb_ide_waiting;
+		MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
+	    	break;
+	    
+	case mb_ide_waiting:
+	    	if (bay->cd_base == 0) {
+			bay->timer = 0;
+			bay->state = mb_up;
+			MBDBG("mediabay%d: up before IDE init\n", i);
+			break;
+	    	} else if (MB_IDE_READY(i)) {
+			bay->timer = 0;
+			bay->state = mb_up;
+			if (bay->cd_index < 0)
+				bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+			if (bay->cd_index == -1) {
+				/* We eventually do a retry */
+				bay->cd_retry++;
+				printk("IDE register error\n");
+				set_mb_power(i, 0);
+			} else {
+				printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
+				MBDBG("mediabay %d IDE ready\n", i);
+			}
+			break;
+	    	}
+	    	if (bay->timer == 0) {
+			printk("\nIDE Timeout in bay %d !\n", i);
+			MBDBG("mediabay%d: nIDE Timeout !\n", i);
+			set_mb_power(i, 0);
+	    	}
+		break;
+#endif // #ifdef CONFIG_BLK_DEV_IDE
+
+	case mb_powering_down:
+	    	bay->state = mb_empty;
+#ifdef CONFIG_BLK_DEV_IDE
+    	        if (bay->cd_index >= 0) {
+			printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
+			       bay->cd_index);
+			ide_unregister(bay->cd_index);
+			bay->cd_index = -1;
+		}
+	    	if (bay->cd_retry) {
+			if (bay->cd_retry > MAX_CD_RETRIES) {
+				/* Should add an error sound (sort of beep in dmasound) */
+				printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i);
+			} else {
+				/* Force a new power down/up sequence */
+				bay->content_id = MB_NO;
+			}
+	    	}
+#endif	    
+		MBDBG("mediabay%d: end of power down\n", i);
+	    	break;
+	}
+}
+
 /*
  * This procedure runs as a kernel thread to poll the media bay
  * once each tick and register and unregister the IDE interface
@@ -260,128 +528,57 @@
 int
 media_bay_task(void *x)
 {
-	volatile struct media_bay_info* bay;
 	int	i = 0;
-	
+
 	strcpy(current->comm, "media-bay");
-	for (;;)
-	{
-		bay = &media_bays[i];
-		poll_media_bay(i);
-		if (bay->content_id != bay->previous_id) {
-			bay->reset_timer = (bay->content_id != MB_NO) ?
-				MB_RESET_COUNT: 0;
-			bay->ready = 0;
-#ifdef CONFIG_BLK_DEV_IDE
-			bay->cd_timer = 0;
-			if (bay->content_id != MB_CD && bay->cd_index >= 0) {
-				printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index);
-				ide_unregister(bay->cd_index);
-				bay->cd_index = -1;
-			}
-#endif
-		} else if (bay->reset_timer) {
-			if (--bay->reset_timer == 0) {
- 				feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-				bay->ready = 1;
-#ifdef CONFIG_BLK_DEV_IDE
-				bay->cd_timer = 0;
-				if (bay->content_id == MB_CD && bay->cd_base != 0)
-					bay->cd_timer = MB_IDE_WAIT;
+#ifdef MB_IGNORE_SIGNALS
+	sigfillset(&current->blocked);
 #endif
-			}
-#ifdef CONFIG_BLK_DEV_IDE
-		} else if (bay->cd_timer
-			   && (--bay->cd_timer == 0
-			       || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
-				   && MB_IDE_READY(i)))
-			   && bay->cd_index < 0) {
-			bay->cd_timer = 0;
-			printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
-			printk("\n");
-			bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
-			if (bay->cd_index == -1)
-				printk("\nCD-ROM badly inserted. Remove it and try again !\n");
-			else
-				printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index);
-#endif
-		}
 
-		bay->previous_id = bay->content_id;
-		if (++i >= media_bay_count) {
-			i = 0;
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(1);
-			if (signal_pending(current))
-				return 0;
-		}
+	for (;;) {
+	    media_bay_step(i);
+
+	    if (++i >= media_bay_count) {
+		i = 0;
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+		if (signal_pending(current))
+		    return 0;
+	    }
 	}
 }
 
 void
 poll_media_bay(int which)
 {
-	int id = MB_CONTENTS(which);
+	volatile struct media_bay_info* bay = &media_bays[which];
+	int id = mb_content(bay);
 
-	if (id == media_bays[which].last_value) {
-	    if (id != media_bays[which].content_id
-	        && ++media_bays[which].value_count >= MB_STABLE_COUNT) {
+	if (id == bay->last_value) {
+	    if (id != bay->content_id
+	        && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
 	        /* If the device type changes without going thru "MB_NO", we force
 	           a pass by "MB_NO" to make sure things are properly reset */
-	        if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) {
-		    set_media_bay(which, MB_NO);
-		    udelay(500);
+	        if ((id != MB_NO) && (bay->content_id != MB_NO)) {
+	            id = MB_NO;
+		    MBDBG("mediabay%d: forcing MB_NO\n", which);
+		}
+		MBDBG("mediabay%d: switching to %d\n", which, id);
+		set_mb_power(which, id != MB_NO);
+		bay->content_id = id;
+		if (id == MB_NO) {
+#ifdef CONFIG_BLK_DEV_IDE
+		    bay->cd_retry = 0;
+#endif
+		    printk(KERN_INFO "media bay %d is empty\n", which);
 		}
- 		set_media_bay(which, id);
  	    }
 	} else {
-		media_bays[which].last_value = id;
-		media_bays[which].value_count = 0;
+		bay->last_value = id;
+		bay->value_count = 0;
 	}
 }
 
-static void
-set_media_bay(int which, int id)
-{
-	volatile struct media_bay_info* bay;
-
-	bay = &media_bays[which];
-	
-	bay->content_id = id;
-	bay->last_value = id;
-	
-	switch (id) {
-	case MB_CD:
-		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-		feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-		udelay(500);
-		feature_set(bay->dev_node, FEATURE_CD_power);
-		printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
-		break;
-	case MB_FD:
-		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-		feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-		feature_set(bay->dev_node, FEATURE_SWIM3_enable);
-		printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
-		break;
-	case MB_NO:
-		feature_clear(bay->dev_node, FEATURE_CD_power);
-		feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
-		feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-		feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-		feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
-		feature_set(bay->dev_node, FEATURE_Mediabay_reset);
-		printk(KERN_INFO "media bay %d is empty\n", which);
-		break;
-	default:
-		feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-		printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
-		       which, id);
-		break;
-	}
-	
-	udelay(500);
-}
 
 #ifdef CONFIG_PMAC_PBOOK
 /*
@@ -392,51 +589,44 @@
 {
 	volatile struct media_bay_info* bay;
 	int i;
-	
+
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 	case PBOOK_SLEEP_REJECT:
 		break;
-		
+
 	case PBOOK_SLEEP_NOW:
 		for (i=0; i<media_bay_count; i++) {
 			bay = &media_bays[i];
-			feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
-			feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
-			feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
-			feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
-			feature_set(bay->dev_node, FEATURE_Mediabay_reset);
-			feature_clear(bay->dev_node, FEATURE_CD_power);
-			out_8(&media_bays[i].addr->contents, 0x70);
+			set_mb_power(i, 0);
+			mdelay(10);
+			feature_clear(bay->dev_node, FEATURE_IOBUS_enable);
 		}
 		break;
 	case PBOOK_WAKE:
 		for (i=0; i<media_bay_count; i++) {
 			bay = &media_bays[i];
-			feature_set(bay->dev_node, FEATURE_Mediabay_enable);
-			/* I suppose this is enough delay to stabilize MB_CONTENT ... */
-			mdelay(10);
 			/* We re-enable the bay using it's previous content
-			   only if it did not change */
-			if (MB_CONTENTS(i) != bay->content_id)
-				continue;
-			set_media_bay(i, bay->content_id);
-			if (bay->content_id == MB_NO)
+			   only if it did not change. Note those bozo timings,
+			   they seem to help the 3400 get it right.
+			 */
+			feature_set(bay->dev_node, FEATURE_IOBUS_enable);
+			mdelay(MB_STABLE_DELAY);
+			if (!bay->pismo)
+				out_8(&bay->addr->contents, 0x70);
+			mdelay(MB_STABLE_DELAY);
+			if (mb_content(bay) != bay->content_id)
 				continue;
-			mdelay(400);
-			/* Clear the bay reset */
-			feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-			/* This small delay makes sure the device has time
-			   to assert the BUSY bit (used by IDE sleep) */
-			udelay(100);
-			/* We reset the state machine timers in case we were
-			   in the middle of a wait loop */
-			if (bay->reset_timer)
-				bay->reset_timer = MB_RESET_COUNT;
-#ifdef CONFIG_BLK_DEV_IDE
-			if (bay->cd_timer)
-				bay->cd_timer = MB_IDE_WAIT;
-#endif
+			set_mb_power(i, 1);
+			bay->last_value = bay->content_id;
+			bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
+			bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+			bay->cd_retry = 0;
+			do {
+				mdelay(1000/HZ);
+				media_bay_step(i);
+			} while((media_bays[i].state != mb_empty) &&
+				(media_bays[i].state != mb_up));
 		}
 		break;
 	}
diff -urN linux-2.2.17-pre2/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- linux-2.2.17-pre2/drivers/macintosh/via-cuda.c	Thu Apr 29 12:53:48 1999
+++ linux/drivers/macintosh/via-cuda.c	Mon Dec  3 22:05:46 2001
@@ -21,6 +21,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/init.h>
+#include <asm/machdep.h>
 
 static volatile unsigned char *via;
 
@@ -496,4 +497,4 @@
 cuda_present(void)
 {
 	return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
-}
\ No newline at end of file
+}
diff -urN linux-2.2.17-pre2/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- linux-2.2.17-pre2/drivers/macintosh/via-pmu.c	Tue Jan  4 10:12:17 2000
+++ linux/drivers/macintosh/via-pmu.c	Mon Dec  3 22:05:46 2001
@@ -10,6 +10,12 @@
  * 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.
+ *
+ *
  */
 #include <stdarg.h>
 #include <linux/config.h>
@@ -39,7 +45,7 @@
 /* Misc minor number allocated for /dev/pmu */
 #define PMU_MINOR	154
 
-static volatile unsigned char *via;
+static volatile unsigned char *via = 0;
 
 /* VIA registers - spaced 0x200 bytes apart */
 #define RS		0x200		/* skip between registers */
@@ -91,16 +97,18 @@
 static unsigned char *reply_ptr;
 static int data_index;
 static int data_len;
-static int adb_int_pending;
+static volatile int adb_int_pending;
 static int pmu_adb_flags;
 static int adb_dev_map = 0;
 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 unsigned char *gpio_reg = NULL;
+static int gpio_irq;
 
 int asleep;
-struct notifier_block *sleep_notifier_list;
 
 static int init_pmu(void);
 static int pmu_queue_request(struct adb_request *req);
@@ -116,6 +124,7 @@
 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);
 #ifdef CONFIG_PMAC_PBOOK
 static void pmu_pass_intr(unsigned char *data, int len);
 #endif
@@ -186,6 +195,7 @@
 	"PowerBook 2400/3400/3500(G3)",
 	"PowerBook G3 Series",
 	"1999 PowerBook G3",
+	"Core99"
 };
 
 int __openfirmware
@@ -198,9 +208,6 @@
 		return 0;
 	if (vias->next != 0)
 		printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
-	
-	feature_set(vias, FEATURE_VIA_enable);
-
 #if 0
 	{ int i;
 
@@ -213,13 +220,16 @@
 	printk("\n"); }
 #endif
 
-	if (vias->n_addrs != 1 || vias->n_intrs != 1) {
+	if (vias->n_addrs < 1 || vias->n_intrs < 1) {
 		printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
 		       vias->n_addrs, vias->n_intrs);
 		if (vias->n_addrs < 1 || vias->n_intrs < 1)
 			return 0;
 	}
 
+	pmu_has_adb = 1;
+	pmu_has_backlight = 1;
+
 	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
 	    || device_is_compatible(vias->parent, "ohare")))
 		pmu_kind = PMU_OHARE_BASED;
@@ -227,23 +237,29 @@
 		pmu_kind = PMU_PADDINGTON_BASED;
 	else if (device_is_compatible(vias->parent, "heathrow"))
 		pmu_kind = PMU_HEATHROW_BASED;
-	else
+	else if (device_is_compatible(vias->parent, "Keylargo")) {
+		pmu_kind = PMU_KEYLARGO_BASED;
+		pmu_has_adb = (find_type_devices("adb") != NULL);
+		pmu_has_backlight = (find_type_devices("backlight") != NULL);
+	} else
 		pmu_kind = PMU_UNKNOWN;
 
 	via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
 
 	out_8(&via[IER], IER_CLR | 0x7f);	/* disable all intrs */
+	out_8(&via[IFR], 0x7f);			/* clear IFR */
 
 	pmu_state = idle;
 
-	if (!init_pmu())
+	if (!init_pmu()) {
 		via = NULL;
+		return 0;
+	}
 
 	adb_controller = &pmu_controller;
 
-	if (via)
-		printk(KERN_INFO "PMU driver initialized for %s\n",
-		       pbook_type[pmu_kind]);
+	printk(KERN_INFO "PMU driver initialized for %s\n",
+	       pbook_type[pmu_kind]);
 
 	return via != 0;
 }
@@ -265,11 +281,28 @@
 		return;
 	}
 
+	if (pmu_kind == PMU_KEYLARGO_BASED) {
+		struct device_node *gpio, *gpiop;
+
+		gpiop = find_devices("gpio");
+		if (gpiop && gpiop->n_addrs) {
+			gpio_reg = ioremap(gpiop->addrs->address, 0x10);
+			gpio = find_devices("extint-gpio1");
+			if (gpio && gpio->parent == gpiop && gpio->n_intrs) {
+				gpio_irq = gpio->intrs[0].line;
+				if (request_irq(gpio_irq, gpio1_interrupt, 0,
+						"GPIO1/ADB", (void *)0))
+					printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n",
+					       gpio->intrs[0].line);
+			}
+		}
+	}
+
 	/* Enable interrupts */
 	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
 
 	pmu_fully_inited = 1;
-	
+
 	/* Enable backlight */
 	pmu_enable_backlight(1);
 }
@@ -323,14 +356,13 @@
 {
     int i, ret;
 
-    if ((vias == NULL) || (!pmu_fully_inited))
-    {
+    if ((vias == NULL) || (!pmu_fully_inited)) {
  	req->complete = 1;
    	return -ENXIO;
-   }
+    }
 
     ret = -EINVAL;
-	
+
     switch (req->data[0]) {
     case PMU_PACKET:
 		for (i = 0; i < req->nbytes - 1; ++i)
@@ -372,6 +404,8 @@
 		}
 		break;
     case ADB_PACKET:
+	    	if (!pmu_has_adb)
+    			return -ENXIO;
 		for (i = req->nbytes - 1; i > 1; --i)
 			req->data[i+2] = req->data[i];
 		req->data[3] = req->nbytes - 2;
@@ -389,7 +423,7 @@
     	req->complete = 1;
     	return ret;
     }
-    	
+    
     if (sync) {
 	while (!req->complete)
 		pmu_poll();
@@ -404,7 +438,7 @@
 {
 	struct adb_request req;
 
-	if ((vias == NULL) || (!pmu_fully_inited))
+	if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
 		return -ENXIO;
 
 	if (devs) {
@@ -426,10 +460,9 @@
 pmu_adb_reset_bus(void)
 {
 	struct adb_request req;
-	long timeout;
 	int save_autopoll = adb_dev_map;
 
-	if ((vias == NULL) || (!pmu_fully_inited))
+	if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
 		return -ENXIO;
 
 	/* anyone got a better idea?? */
@@ -439,31 +472,21 @@
 	req.done = NULL;
 	req.data[0] = PMU_ADB_CMD;
 	req.data[1] = 0;
-	req.data[2] = 3; /* ADB_BUSRESET ??? */
+	req.data[2] = ADB_BUSRESET; /* 3 ??? */
 	req.data[3] = 0;
 	req.data[4] = 0;
 	req.reply_len = 0;
 	req.reply_expected = 1;
-	if (pmu_queue_request(&req) != 0)
-	{
+	if (pmu_queue_request(&req) != 0) {
 		printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
 		return -EIO;
 	}
 	while (!req.complete)
 		pmu_poll();
-	timeout = 100000;
-	while (!req.complete) {
-		if (--timeout < 0) {
-			printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
-			return -EIO;
-		}
-		udelay(10);
-		pmu_poll();
-	}
 
 	if (save_autopoll != 0)
 		pmu_adb_autopoll(save_autopoll);
-		
+
 	return 0;
 }
 
@@ -537,6 +560,8 @@
 	return 0;
 }
 
+/* New PMU seems to be very sensitive to those timings, so we make sure
+ * PCI is flushed immediately */
 static void __openfirmware
 send_byte(int x)
 {
@@ -545,6 +570,7 @@
 	out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
 	out_8(&v[SR], x);
 	out_8(&v[B], in_8(&v[B]) & ~TREQ);		/* assert TREQ */
+	(void)in_8(&v[B]);
 }
 
 static void __openfirmware
@@ -554,10 +580,11 @@
 
 	out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
 	in_8(&v[SR]);		/* resets SR */
-	out_8(&v[B], in_8(&v[B]) & ~0x10);
+	out_8(&v[B], in_8(&v[B]) & ~TREQ);
+	(void)in_8(&v[B]);
 }
 
-static int disable_poll;
+static volatile int disable_poll;
 
 static void __openfirmware
 pmu_start()
@@ -594,7 +621,8 @@
 	if (disable_poll)
 		return;
 	ie = _disable_interrupts();
-	if (via[IFR] & (SR_INT | CB1_INT))
+	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);
 }
@@ -604,7 +632,12 @@
 {
 	int intr;
 	int nloop = 0;
+	unsigned long flags;
 
+	/* 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();
 	++disable_poll;
 	while ((intr = in_8(&via[IFR])) != 0) {
 		if (++nloop > 1000) {
@@ -623,6 +656,9 @@
 			out_8(&via[IFR], intr);
 		}
 	}
+	if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)
+		adb_int_pending = 1;
+
 	if (pmu_state == idle) {
 		if (adb_int_pending) {
 			pmu_state = intack;
@@ -633,9 +669,16 @@
 		}
 	}
 	--disable_poll;
+	restore_flags(flags);
 }
 
 static void __openfirmware
+gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+	via_pmu_interrupt(0, 0, 0);
+ }
+ 
+static void __openfirmware
 pmu_sr_intr(struct pt_regs *regs)
 {
 	struct adb_request *req;
@@ -646,9 +689,17 @@
 		out_8(&via[IFR], SR_INT);
 		return;
 	}
-	if (via[B] & TACK)
+	/* This one seems to appear with PMU99. According to OF methods,
+	 * the protocol didn't change...
+	 */
+	if (via[B] & TACK) {
+		while ((in_8(&via[B]) & TACK) != 0)
+			;
+#if 0
 		printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n",
 		       via[B]);
+#endif
+	}
 
 	/* reset TREQ and wait for TACK to go high */
 	out_8(&via[B], in_8(&via[B]) | TREQ);
@@ -810,9 +861,9 @@
 {
 	struct adb_request req;
 
-	if (vias == NULL)
+	if ((vias == NULL) || !pmu_has_backlight)
 		return;
-		
+
 	/* first call: get current backlight value */
 	if (on && backlight_level < 0) {
 		switch (pmu_kind) {
@@ -831,6 +882,7 @@
 			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
@@ -861,7 +913,7 @@
 {
 	int bright;
 
-	if (vias == NULL)
+	if ((vias == NULL) || !pmu_has_backlight)
 		return ;
 
 	backlight_level = level;
@@ -908,12 +960,12 @@
 	struct adb_request req;
 
 	_disable_interrupts();
-	
+
 	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
 					PMU_INT_TICK );
 	while(!req.complete)
 		pmu_poll();
-	
+
 	pmu_request(&req, NULL, 1, PMU_RESET);
 	while(!req.complete || (pmu_state != idle))
 		pmu_poll();
@@ -927,7 +979,7 @@
 	struct adb_request req;
 
 	_disable_interrupts();
-	
+
 	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
 					PMU_INT_TICK );
 	while(!req.complete)
@@ -944,7 +996,7 @@
 int
 pmu_present(void)
 {
-	return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+	return via != 0;
 }
 
 #ifdef CONFIG_PMAC_PBOOK
@@ -979,7 +1031,7 @@
 
 /* Sleep is broadcast last-to-first */
 static int
-broadcast_sleep(int when, int can_cancel)
+broadcast_sleep(int when, int fallback)
 {
 	int ret = PBOOK_SLEEP_OK;
 	struct list_head *list;
@@ -989,8 +1041,15 @@
 	     list = list->prev) {
 		current = list_entry(list, struct pmu_sleep_notifier, list);
 		ret = current->notifier_call(current, when);
-		if (can_cancel && (ret != PBOOK_SLEEP_OK))
+		if (ret != PBOOK_SLEEP_OK) {
+			printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
+			       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);
+			}
 			return ret;
+		}
 	}
 	return ret;
 }
@@ -1127,9 +1186,8 @@
 			ioremap(macio->addrs[0].address, 0x40);
 
 	/* Notify device drivers */
-	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
 	if (ret != PBOOK_SLEEP_OK) {
-		broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
 		printk("pmu: sleep rejected\n");
 		return -EBUSY;
 	}
@@ -1142,7 +1200,12 @@
 	 * vmalloc's are done before actual sleep of block drivers */
 	fsync_dev(0);
 
-	broadcast_sleep(PBOOK_SLEEP_NOW, 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/4); time_before(jiffies, wait); )
@@ -1210,7 +1273,7 @@
 	/* Restore L2 cache */
 	if (save_l2cr)
  		_set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
-	
+
 	/* reenable interrupts */
 	sleep_restore_intrs();
 
@@ -1231,9 +1294,8 @@
 	struct adb_request sleep_req;
 
 	/* Notify device drivers */
-	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
 	if (ret != PBOOK_SLEEP_OK) {
-		broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
 		printk("pmu: sleep rejected\n");
 		return -EBUSY;
 	}
@@ -1246,7 +1308,12 @@
 	 * vmalloc's are done before actual sleep of block drivers */
 	fsync_dev(0);
 
-	broadcast_sleep(PBOOK_SLEEP_NOW, 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/4); time_before(jiffies, wait); )
@@ -1473,18 +1540,24 @@
 			error = powerbook_sleep_G3();
 			break;
 		default:
-			error = ENOSYS;
+			error = -ENOSYS;
 		}
 		return error;
 	case PMU_IOC_GET_BACKLIGHT:
+		if (!pmu_has_backlight)
+			return -ENOSYS;
 		return put_user(backlight_level, (__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);
 		return error;
 	case PMU_IOC_GET_MODEL:
 	    	return put_user(pmu_kind, (__u32 *)arg);
+	case PMU_IOC_HAS_ADB:
+		return put_user(pmu_has_adb, (__u32 *)arg);
 	}
 	return -EINVAL;
 }
@@ -1526,7 +1599,6 @@
 
 static inline void polled_send_byte(volatile unsigned char *via, int x)
 {
-	xmon_printf("s%.2x", x);
 	via[ACR] |= SR_OUT | SR_EXT; eieio();
 	via[SR] = x; eieio();
 	polled_handshake(via);
@@ -1540,7 +1612,6 @@
 	x = via[SR]; eieio();
 	polled_handshake(via);
 	x = via[SR]; eieio();
-	xmon_printf("r%.2x", x);
 	return x;
 }
 
diff -urN linux-2.2.17-pre2/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.2.17-pre2/drivers/net/Config.in	Mon Dec  3 22:05:41 2001
+++ linux/drivers/net/Config.in	Mon Dec  3 22:05:46 2001
@@ -47,6 +47,7 @@
   if [ "$CONFIG_PPC" = "y" ]; then
     tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE
     tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC
+    tristate 'GMAC (G4/iBook ethernet) support' CONFIG_GMAC
     tristate 'Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E
   fi
   if [ "$CONFIG_ZORRO" = "y" ]; then
diff -urN linux-2.2.17-pre2/drivers/net/Makefile linux/drivers/net/Makefile
--- linux-2.2.17-pre2/drivers/net/Makefile	Mon Dec  3 22:05:41 2001
+++ linux/drivers/net/Makefile	Mon Dec  3 22:05:46 2001
@@ -1253,6 +1253,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_GMAC),y)
+L_OBJS += gmac.o
+else
+  ifeq ($(CONFIG_GMAC),m)
+  M_OBJS += gmac.o
+  endif
+endif
+
 ifeq ($(CONFIG_NCR885E),y)
 L_OBJS += ncr885e.o
 else
diff -urN linux-2.2.17-pre2/drivers/net/Space.c linux/drivers/net/Space.c
--- linux-2.2.17-pre2/drivers/net/Space.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/net/Space.c	Mon Dec  3 22:05:46 2001
@@ -103,6 +103,7 @@
 extern int tlan_probe(struct device *);
 extern int mace_probe(struct device *);
 extern int bmac_probe(struct device *);
+extern int gmac_probe(struct device *);
 extern int ncr885e_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 extern int ethertap_probe(struct device *dev);
@@ -469,6 +470,9 @@
 #endif
 #ifdef CONFIG_BMAC
 	{bmac_probe, 0},
+#endif
+#ifdef CONFIG_GMAC
+	{gmac_probe, 0},
 #endif
 #ifdef CONFIG_NCR885E
 	{ncr885e_probe, 0},
diff -urN linux-2.2.17-pre2/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- linux-2.2.17-pre2/drivers/net/de4x5.c	Mon Aug  9 12:04:39 1999
+++ linux/drivers/net/de4x5.c	Mon Dec  3 22:05:46 2001
@@ -653,12 +653,20 @@
 #define ALIGN64     ((u_long)64 - 1)    /* 16 longword align */
 #define ALIGN128    ((u_long)128 - 1)   /* 32 longword align */
 
+#ifndef __powerpc__
 #define ALIGN         ALIGN32           /* Keep the DC21040 happy... */
 #define CACHE_ALIGN   CAL_16LONG
 #define DESC_SKIP_LEN DSL_0             /* Must agree with DESC_ALIGN */
 /*#define DESC_ALIGN    u32 dummy[4];  / * Must agree with DESC_SKIP_LEN */
 #define DESC_ALIGN
 
+#else /* __powerpc__ */
+#define ALIGN         ALIGN32           /* Keep the DC21040 happy... */
+#define CACHE_ALIGN   CAL_8LONG
+#define DESC_SKIP_LEN DSL_4             /* Must agree with DESC_ALIGN */
+#define DESC_ALIGN    u32 dummy[4];  	/* Must agree with DESC_SKIP_LEN */
+#endif /* __powerpc__ */
+
 #ifndef DEC_ONLY                        /* See README.de4x5 for using this */
 static int dec_only = 0;
 #else
@@ -763,6 +771,9 @@
 struct de4x5_private {
     char adapter_name[80];                  /* Adapter name                 */
     u_long interrupt;                       /* Aligned ISR flag             */
+#ifdef __powerpc__
+    u_long dummy[3];			    /* Keep rx_ring 32-byte aligned */
+#endif
     struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring           */
     struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring           */
     struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
diff -urN linux-2.2.17-pre2/drivers/net/gmac.c linux/drivers/net/gmac.c
--- linux-2.2.17-pre2/drivers/net/gmac.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/gmac.c	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,614 @@
+/*
+ * Network device driver for the GMAC ethernet controller on
+ * Apple G4 Powermacs.
+ *
+ * Copyright (C) 2000 Paul Mackerras.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include "gmac.h"
+
+#define DEBUG_PHY
+
+#define NTX		32		/* must be power of 2 */
+#define NRX		32		/* must be power of 2 */
+#define RX_BUFLEN	(ETH_FRAME_LEN + 8)
+
+struct gmac_dma_desc {
+	unsigned int	cmd;
+	unsigned int	status;
+	unsigned int	address;	/* phys addr, low 32 bits */
+	unsigned int	hi_addr;
+};
+
+/* Bits in cmd */
+#define RX_OWN	0x80000000		/* 1 = owned by chip */
+#define TX_SOP	0x80000000
+#define TX_EOP	0x40000000
+
+struct gmac {
+	volatile unsigned int *regs;	/* hardware registers, virtual addr */
+	volatile unsigned int *sysregs;
+	unsigned long	desc_page;	/* page for DMA descriptors */
+	volatile struct gmac_dma_desc *rxring;
+	struct sk_buff	*rx_buff[NRX];
+	int		next_rx;
+	volatile struct gmac_dma_desc *txring;
+	struct sk_buff	*tx_buff[NTX];
+	int		next_tx;
+	int		tx_gone;
+	unsigned char	tx_full;
+	int		phy_addr;
+	int		full_duplex;
+	struct net_device_stats stats;
+};
+
+#define GM_OUT(r, v)	out_le32(gm->regs + (r)/4, (v))
+#define GM_IN(r)	in_le32(gm->regs + (r)/4)
+#define GM_BIS(r, v)	GM_OUT((r), GM_IN(r) | (v))
+#define GM_BIC(r, v)	GM_OUT((r), GM_IN(r) & ~(v))
+
+#define PHY_B5400	0x6040
+#define PHY_B5201	0x6212
+
+static unsigned char dummy_buf[RX_BUFLEN+2];
+static struct device *gmacs = NULL;
+
+/* Prototypes */
+static int mii_read(struct gmac *gm, int phy, int r);
+static int mii_write(struct gmac *gm, int phy, int r, int v);
+static void powerup_transceiver(struct gmac *gm);
+static int gmac_reset(struct device *dev);
+static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
+static void gmac_init_rings(struct gmac *gm);
+static void gmac_start_dma(struct gmac *gm);
+static int gmac_open(struct device *dev);
+static int gmac_close(struct device *dev);
+static int gmac_xmit_start(struct sk_buff *skb, struct device *dev);
+static int gmac_tx_cleanup(struct gmac *gm);
+static void gmac_receive(struct device *dev);
+static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats *gmac_stats(struct device *dev);
+int gmac_probe(struct device *dev);
+
+/* Stuff for talking to the physical-layer chip */
+static int
+mii_read(struct gmac *gm, int phy, int r)
+{
+	int timeout;
+
+	GM_OUT(MIFFRAME, 0x60020000 | (phy << 23) | (r << 18));
+	for (timeout = 1000; timeout > 0; --timeout) {
+		udelay(20);
+		if (GM_IN(MIFFRAME) & 0x10000)
+			return GM_IN(MIFFRAME) & 0xffff;
+	}
+	return -1;
+}
+
+static int
+mii_write(struct gmac *gm, int phy, int r, int v)
+{
+	int timeout;
+
+	GM_OUT(MIFFRAME, 0x50020000 | (phy << 23) | (r << 18) | (v & 0xffff));
+	for (timeout = 1000; timeout > 0; --timeout) {
+		udelay(20);
+		if (GM_IN(MIFFRAME) & 0x10000)
+			return 0;
+	}
+	return -1;
+}
+
+static void 
+mii_poll_start(struct gmac *gm)
+{
+	unsigned int tmp;
+	
+	/* Start the MIF polling on the external transceiver. */
+	tmp = GM_IN(MIFCONFIG);
+	tmp &= ~(GMAC_MIF_CFGPR_MASK | GMAC_MIF_CFGPD_MASK);
+	tmp |= ((gm->phy_addr & 0x1f) << GMAC_MIF_CFGPD_SHIFT);
+	tmp |= (0x19 << GMAC_MIF_CFGPR_SHIFT);
+	tmp |= GMAC_MIF_CFGPE;
+	GM_OUT(MIFCONFIG, tmp);
+
+	/* Let the bits set. */
+	udelay(GMAC_MIF_POLL_DELAY);
+
+	GM_OUT(MIFINTMASK, 0xffc0);
+}
+
+static void 
+mii_poll_stop(struct gmac *gm)
+{
+	GM_OUT(MIFINTMASK, 0xffff);
+	GM_BIC(MIFCONFIG, GMAC_MIF_CFGPE);
+	udelay(GMAC_MIF_POLL_DELAY);
+}
+
+static void
+mii_interrupt(struct gmac *gm)
+{
+	unsigned long	flags;
+	int		phy_status;
+	
+	save_flags(flags);
+	cli();
+
+	mii_poll_stop(gm);
+
+	/* May the status change before polling is re-enabled ? */
+	mii_poll_start(gm);
+	
+	/* We read the Auxilliary Status Summary register */
+	phy_status = mii_read(gm, gm->phy_addr, 0x19);
+#ifdef DEBUG_PHY
+	printk("mii_interrupt, phy_status: %x\n", phy_status);
+#endif
+	/* Auto-neg. complete ? */
+	if (phy_status & 0x8000) {
+		int full_duplex = 0;
+		switch((phy_status >> 8) & 0x7) {
+			case 2:
+			case 5:
+				full_duplex = 1;
+				break;
+		}
+		if (full_duplex != gm->full_duplex) {
+			GM_BIC(TXMAC_CONFIG, 1);
+			udelay(200);
+			if (full_duplex) {
+				printk("full duplex active\n");
+				GM_OUT(TXMAC_CONFIG, 6);
+				GM_OUT(XIF_CONFIG, 1);
+			} else {
+				printk("half duplex active\n");
+				GM_OUT(TXMAC_CONFIG, 0);
+				GM_OUT(XIF_CONFIG, 5);
+			}
+			GM_BIS(TXMAC_CONFIG, 1);
+			gm->full_duplex = full_duplex;
+		}
+	}
+
+	restore_flags(flags);
+}
+
+static void
+powerup_transceiver(struct gmac *gm)
+{
+	int phytype = mii_read(gm, 0, 3);
+#ifdef DEBUG_PHY
+	int i;
+#endif	
+	switch (phytype) {
+	case PHY_B5400:
+		mii_write(gm, 0, 0, mii_read(gm, 0, 0) & ~0x800);
+		mii_write(gm, 31, 30, mii_read(gm, 31, 30) & ~8);
+		break;
+	case PHY_B5201:
+		mii_write(gm, 0, 30, mii_read(gm, 0, 30) & ~8);
+		break;
+	default:
+		printk(KERN_ERR "GMAC: unknown PHY type %x\n", phytype);
+	}
+	/* Check this */
+	gm->phy_addr = 0;
+	gm->full_duplex = 0;
+
+#ifdef DEBUG_PHY
+	printk("PHY regs:\n");
+	for (i=0; i<0x20; i++) {
+		printk("%04x ", mii_read(gm, 0, i)); 
+		if ((i % 4) == 3)
+			printk("\n");
+	}
+#endif
+}
+
+static int
+gmac_reset(struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+	int timeout;
+
+	/* turn on GB clock */
+	out_le32(gm->sysregs + 0x20/4, in_le32(gm->sysregs + 0x20/4) | 2);
+	udelay(10);
+	GM_OUT(SW_RESET, 3);
+	for (timeout = 100; timeout > 0; --timeout) {
+		mdelay(10);
+		if ((GM_IN(SW_RESET) & 3) == 0)
+			return 0;
+	}
+	printk(KERN_ERR "GMAC: reset failed!\n");
+	return -1;
+}
+
+static void
+gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
+{
+	int i;
+
+	GM_OUT(RANSEED, 937);
+	GM_OUT(DATAPATHMODE, 4);
+	mii_write(gm, 0, 0, 0x1000);
+	GM_OUT(TXDMA_CONFIG, 0xffc00);
+	GM_OUT(RXDMA_CONFIG, 0);
+	GM_OUT(MACPAUSE, 0x1bf0);
+	GM_OUT(IPG0, 0);
+	GM_OUT(IPG1, 8);
+	GM_OUT(IPG2, 4);
+	GM_OUT(MINFRAMESIZE, 64);
+	GM_OUT(MAXFRAMESIZE, 2000);
+	GM_OUT(PASIZE, 7);
+	GM_OUT(JAMSIZE, 4);
+	GM_OUT(ATTEMPT_LIMIT, 16);
+	GM_OUT(SLOTTIME, 64);
+	GM_OUT(MACCNTL_TYPE, 0x8808);
+	GM_OUT(MAC_ADDR_0, (mac_addr[4] << 8) + mac_addr[5]);
+	GM_OUT(MAC_ADDR_1, (mac_addr[2] << 8) + mac_addr[3]);
+	GM_OUT(MAC_ADDR_2, (mac_addr[0] << 8) + mac_addr[1]);
+	GM_OUT(MAC_ADDR_3, 0);
+	GM_OUT(MAC_ADDR_4, 0);
+	GM_OUT(MAC_ADDR_5, 0);
+	GM_OUT(MAC_ADDR_6, 0x0180);
+	GM_OUT(MAC_ADDR_7, 0xc200);
+	GM_OUT(MAC_ADDR_8, 0x0001);
+	GM_OUT(MAC_ADDR_FILTER_0, 0);
+	GM_OUT(MAC_ADDR_FILTER_1, 0);
+	GM_OUT(MAC_ADDR_FILTER_2, 0);
+	GM_OUT(MAC_ADDR_FILTER_MASK21, 0);
+	GM_OUT(MAC_ADDR_FILTER_MASK0, 0);
+	for (i = 0; i < 27; ++i)
+		GM_OUT(MAC_HASHTABLE + i, 0);
+	GM_OUT(MACCNTL_CONFIG, 0);
+	/* default to half duplex */
+	GM_OUT(TXMAC_CONFIG, 0);
+	GM_OUT(XIF_CONFIG, 5);
+}
+
+static void
+gmac_init_rings(struct gmac *gm)
+{
+	int i;
+	struct sk_buff *skb;
+	unsigned char *data;
+	struct gmac_dma_desc *ring;
+
+	/* init rx ring */
+	ring = (struct gmac_dma_desc *) gm->rxring;
+	memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+	for (i = 0; i < NRX; ++i, ++ring) {
+		data = dummy_buf;
+		gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+		if (skb != 0) {
+			/*skb_reserve(skb, 2);*/
+			data = skb->data;
+		}
+		st_le32(&ring->address, virt_to_bus(data));
+		st_le32(&ring->cmd, RX_OWN);
+	}
+
+	/* init tx ring */
+	ring = (struct gmac_dma_desc *) gm->txring;
+	memset(ring, 0, NRX * sizeof(struct gmac_dma_desc));
+
+	/* set pointers in chip */
+	mb();
+	GM_OUT(RXDMA_BASE_HIGH, 0);
+	GM_OUT(RXDMA_BASE_LOW, virt_to_bus(gm->rxring));
+	GM_OUT(TXDMA_BASE_HIGH, 0);
+	GM_OUT(TXDMA_BASE_LOW, virt_to_bus(gm->txring));
+}
+
+static void
+gmac_start_dma(struct gmac *gm)
+{
+	GM_BIS(RXDMA_CONFIG, 1);
+	GM_BIS(RXMAC_CONFIG, 1);
+	GM_OUT(RXDMA_KICK, NRX);
+	GM_BIS(TXDMA_CONFIG, 1);
+	GM_BIS(TXMAC_CONFIG, 1);
+}
+
+static int gmac_open(struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+
+	if (gmac_reset(dev))
+		return -EIO;
+
+	MOD_INC_USE_COUNT;
+
+	powerup_transceiver(gm);
+	gmac_mac_init(gm, dev->dev_addr);
+	gmac_init_rings(gm);
+	gmac_start_dma(gm);
+	mii_interrupt(gm);
+
+	GM_OUT(INTR_DISABLE, 0xfffdffe8);
+
+	return 0;
+}
+
+static int gmac_close(struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+	int i;
+
+	mii_poll_stop(gm);
+	
+	GM_BIC(RXDMA_CONFIG, 1);
+	GM_BIC(RXMAC_CONFIG, 1);
+	GM_BIC(TXDMA_CONFIG, 1);
+	GM_BIC(TXMAC_CONFIG, 1);
+	GM_OUT(INTR_DISABLE, ~0U);
+	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;
+		}
+	}
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int gmac_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+	volatile struct gmac_dma_desc *dp;
+	unsigned long flags;
+	int i;
+
+	save_flags(flags); cli();
+	i = gm->next_tx;
+	if (gm->tx_buff[i] != 0) {
+		/* buffer is full, can't send this packet at the moment */
+		dev->tbusy = 1;
+		gm->tx_full = 1;
+		restore_flags(flags);
+		return 1;
+	}
+	gm->next_tx = (i + 1) & (NTX - 1);
+	gm->tx_buff[i] = skb;
+	restore_flags(flags);
+
+	dp = &gm->txring[i];
+	dp->status = 0;
+	dp->hi_addr = 0;
+	st_le32(&dp->address, virt_to_bus(skb->data));
+	mb();
+	st_le32(&dp->cmd, TX_SOP | TX_EOP | skb->len);
+	mb();
+
+	GM_OUT(TXDMA_KICK, gm->next_tx);
+
+	return 0;
+}
+
+static int gmac_tx_cleanup(struct gmac *gm)
+{
+	int i = gm->tx_gone;
+	volatile struct gmac_dma_desc *dp;
+	struct sk_buff *skb;
+	int ret = 0;
+	int gone = GM_IN(TXDMA_COMPLETE);
+
+	while (i != gone) {
+		skb = gm->tx_buff[i];
+		if (skb == NULL)
+			break;
+		dp = &gm->txring[i];
+		gm->stats.tx_bytes += skb->len;
+		++gm->stats.tx_packets;
+		gm->tx_buff[i] = NULL;
+		dev_kfree_skb(skb);
+		if (++i >= NTX)
+			i = 0;
+	}
+	if (i != gm->tx_gone) {
+		ret = gm->tx_full;
+		gm->tx_gone = i;
+		gm->tx_full = 0;
+	}
+	return ret;
+}
+
+static void gmac_receive(struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+	int i = gm->next_rx;
+	volatile struct gmac_dma_desc *dp;
+	struct sk_buff *skb;
+	int len;
+	unsigned char *data;
+
+	for (;;) {
+		dp = &gm->rxring[i];
+		if (ld_le32(&dp->cmd) & RX_OWN)
+			break;
+		len = (ld_le32(&dp->cmd) >> 16) & 0x7fff;
+		skb = gm->rx_buff[i];
+		if (skb == 0) {
+			++gm->stats.rx_dropped;
+		} else if (ld_le32(&dp->status) & 0x40000000) {
+			++gm->stats.rx_errors;
+			dev_kfree_skb(skb);
+		} else {
+			skb_put(skb, len);
+			skb->dev = dev;
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			gm->stats.rx_bytes += skb->len;
+			++gm->stats.rx_packets;
+		}
+		data = dummy_buf;
+		gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2);
+		if (skb != 0) {
+			/*skb_reserve(skb, 2);*/
+			data = skb->data;
+		}
+		st_le32(&dp->address, virt_to_bus(data));
+		dp->hi_addr = 0;
+		mb();
+		st_le32(&dp->cmd, RX_OWN);
+		if (++i >= NRX)
+			i = 0;
+	}
+	gm->next_rx = i;
+}
+
+static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct gmac *gm = (struct gmac *) dev->priv;
+	unsigned int status;
+
+	status = GM_IN(INTR_STATUS);
+	GM_OUT(INTR_ACK, status);
+	
+	if (status & GMAC_IRQ_MIF) {
+		mii_interrupt(gm);
+	}
+	gmac_receive(dev);
+	if (gmac_tx_cleanup(gm)){
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+}
+
+static struct net_device_stats *gmac_stats(struct device *dev)
+{
+	struct gmac *gm = (struct gmac *) dev->priv;
+
+	return &gm->stats;
+}
+
+int gmac_probe(struct device *dev)
+{
+	static int gmacs_found;
+	static struct device_node *next_gmac;
+	struct device_node *gmac;
+	struct gmac *gm;
+	unsigned long descpage;
+	unsigned char *addr;
+	int i;
+
+	/*
+	 * We could (and maybe should) do this using PCI scanning
+	 * for vendor/device ID 0x106b/0x21.
+	 */
+	if (!gmacs_found) {
+		next_gmac = find_compatible_devices("network", "gmac");
+		gmacs_found = 1;
+	}
+	if ((gmac = next_gmac) == 0)
+		return -ENODEV;
+	next_gmac = gmac->next;
+
+	if (gmac->n_addrs < 1 || gmac->n_intrs < 1) {
+		printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n",
+		       gmac->full_name, gmac->n_addrs, gmac->n_intrs);
+		return -ENODEV;
+	}
+
+	dev = init_etherdev(0, sizeof(struct gmac));
+	memset(dev->priv, 0, sizeof(struct gmac));
+
+	gm = (struct gmac *) dev->priv;
+	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;
+
+	addr = get_property(gmac, "local-mac-address", NULL);
+	if (addr == NULL) {
+		printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
+		       gmac->full_name);
+		return -EAGAIN;
+	}
+
+	printk(KERN_INFO "%s: GMAC at", dev->name);
+	for (i = 0; i < 6; ++i) {
+		dev->dev_addr[i] = addr[i];
+		printk("%c%.2x", (i? ':': ' '), addr[i]);
+	}
+	printk("\n");
+
+	descpage = get_free_page(GFP_KERNEL);
+	if (descpage == 0) {
+		printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
+		return -EAGAIN;
+	}
+
+	gm->desc_page = descpage;
+	gm->rxring = (volatile struct gmac_dma_desc *) descpage;
+	gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
+
+	gm->phy_addr = 0;
+	
+	dev->open = gmac_open;
+	dev->stop = gmac_close;
+	dev->hard_start_xmit = gmac_xmit_start;
+	dev->get_stats = gmac_stats;
+
+	ether_setup(dev);
+
+	if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) {
+		printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
+		return -EAGAIN;
+	}
+
+	gmacs = dev;
+
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac GMAC driver.");
+
+int init_module(void)
+{
+	if (gmacs != NULL)
+		return -EBUSY;
+	return gmac_probe(NULL);
+}
+
+void cleanup_module(void)
+{
+	struct gmac *gm;
+
+	/* XXX should handle more than one */
+	if (gmacs == NULL)
+		return;
+
+	gm = (struct gmac *) gmacs->priv;
+	free_irq(gmacs->irq, gmac_interrupt);
+	free_page(gm->desc_page);
+	unregister_netdev(gmacs);
+	kfree(gmacs);
+	gmacs = NULL;
+}
+
+#endif
diff -urN linux-2.2.17-pre2/drivers/net/gmac.h linux/drivers/net/gmac.h
--- linux-2.2.17-pre2/drivers/net/gmac.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/gmac.h	Mon Dec  3 22:05:46 2001
@@ -0,0 +1,113 @@
+/*
+ * Definitions for the GMAC ethernet chip, used in the
+ * Apple G4 powermac.
+ */
+
+/* Register offsets */
+#define	INTR_STATUS		0x000c
+#define INTR_DISABLE		0x0010
+#define INTR_ACK		0x0014
+#define SW_RESET		0x1010
+#define TXDMA_KICK		0x2000
+#define TXDMA_CONFIG		0x2004
+#define TXDMA_BASE_LOW		0x2008
+#define TXDMA_BASE_HIGH		0x200c
+#define TXDMA_STATE_MACH	0x2028
+#define TXDMA_COMPLETE		0x2100
+#define RXDMA_CONFIG		0x4000
+#define RXDMA_BASE_LOW		0x4004
+#define RXDMA_BASE_HIGH		0x4008
+#define RXDMA_KICK		0x4100
+#define MACPAUSE		0x6008
+#define TXMAC_STATUS		0x6010
+#define TXMAC_CONFIG		0x6030
+#define RXMAC_CONFIG		0x6034
+#define MACCNTL_CONFIG		0x6038
+#define XIF_CONFIG		0x603c
+#define IPG0			0x6040
+#define IPG1			0x6044
+#define IPG2			0x6048
+#define SLOTTIME		0x604c
+#define MINFRAMESIZE		0x6050
+#define MAXFRAMESIZE		0x6054
+#define PASIZE			0x6058
+#define JAMSIZE			0x605c
+#define ATTEMPT_LIMIT		0x6060
+#define MACCNTL_TYPE		0x6064
+#define MAC_ADDR_0		0x6080
+#define MAC_ADDR_1		0x6084
+#define MAC_ADDR_2		0x6088
+#define MAC_ADDR_3		0x608c
+#define MAC_ADDR_4		0x6090
+#define MAC_ADDR_5		0x6094
+#define MAC_ADDR_6		0x6098
+#define MAC_ADDR_7		0x609c
+#define MAC_ADDR_8		0x60a0
+#define MAC_ADDR_FILTER_0	0x60a4
+#define MAC_ADDR_FILTER_1	0x60a8
+#define MAC_ADDR_FILTER_2	0x60ac
+#define MAC_ADDR_FILTER_MASK21	0x60b0
+#define MAC_ADDR_FILTER_MASK0	0x60b4
+#define MAC_HASHTABLE		0x60c0
+#define RANSEED			0x6130
+#define MIFFRAME		0x620c
+#define MIFCONFIG		0x6210
+#define MIFINTMASK		0x6214
+#define MIFSTATUS		0x6218
+#define DATAPATHMODE		0x9050
+
+/* -- 0x000C	R-C	Global Interrupt status. 
+ * d: 0x00000000	bits 0-6 cleared on read (C)
+ */
+#define GMAC_IRQ_TX_INT_ME	0x00000001	/* C Frame with INT_ME bit set in fifo */
+#define GMAC_IRQ_TX_ALL		0x00000002	/* C TX descriptor ring empty */
+#define GMAC_IRQ_TX_DONE	0x00000004	/* C moved from host to TX fifo */
+#define GMAC_IRQ_RX_DONE	0x00000010	/* C moved from RX fifo to host */
+#define GMAC_IRQ_RX_NO_BUF	0x00000020	/* C No RX buffer available */
+#define GMAC_IRQ_RX_TAG_ERR	0x00000040	/* C RX tag error */
+
+#define GMAC_IRQ_PCS		0x00002000	/* PCS interrupt ? */
+#define GMAC_IRQ_MAC_TX		0x00004000	/* MAC tx register set */
+#define GMAC_IRQ_MAC_RX		0x00008000	/* MAC rx register set  */
+#define GMAC_IRQ_MAC_CTRL	0x00010000	/* MAC control register set  */
+#define GMAC_IRQ_MIF		0x00020000	/* MIF status register set */
+#define GMAC_IRQ_BUS_ERROR	0x00040000	/* Bus error status register set */
+
+#define GMAC_IRQ_TX_COMP	0xfff80000	/* TX completion mask */
+
+/* -- 0x6210	RW	MIF config reg
+ */
+
+#define	GMAC_MIF_CFGPS			0x00000001	/* PHY Select */
+#define	GMAC_MIF_CFGPE			0x00000002	/* Poll Enable */
+#define	GMAC_MIF_CFGBB			0x00000004	/* Bit Bang Enable */
+#define	GMAC_MIF_CFGPR_MASK		0x000000f8	/* Poll Register address */
+#define	GMAC_MIF_CFGPR_SHIFT		3
+#define	GMAC_MIF_CFGM0			0x00000100	/* MDIO_0 Data / MDIO_0 attached */
+#define	GMAC_MIF_CFGM1			0x00000200	/* MDIO_1 Data / MDIO_1 attached */
+#define	GMAC_MIF_CFGPD_MASK		0x00007c00	/* Poll Device PHY address */
+#define	GMAC_MIF_CFGPD_SHIFT		10
+
+#define	GMAC_MIF_POLL_DELAY		200
+
+#define	GMAC_INTERNAL_PHYAD		1		/* PHY address for int. transceiver */
+#define	GMAC_EXTERNAL_PHYAD		0		/* PHY address for ext. transceiver */
+
+
+/* -- 0x6214	RW	MIF interrupt mask reg
+ *			same as basic/status Register
+ */
+
+/* -- 0x6214	RW	MIF basic/status reg
+ *			The Basic portion of this register indicates the last
+ *			value of the register read indicated in the POLL REG field
+ *			of the Configuration Register.
+ *			The Status portion indicates bit(s) that have changed.
+ *			The MIF Mask register is corresponding to this register in
+ *			terms of the bit(s) that need to be masked for generating
+ *			interrupt on the MIF Interrupt Bit of the Global Status Rgister.
+ */
+
+#define	GMAC_MIF_STATUS			0x0000ffff	/* 0-15 : Status */
+#define	GMAC_MIF_BASIC			0xffff0000	/* 16-31 : Basic register */
+
diff -urN linux-2.2.17-pre2/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- linux-2.2.17-pre2/drivers/net/sunhme.c	Tue Jan  4 10:12:18 2000
+++ linux/drivers/net/sunhme.c	Mon Dec  3 22:05:46 2001
@@ -2336,6 +2336,11 @@
 
 	dev->interrupt = 1;
 
+	if ((happy_status & (GREG_STAT_TXALL | GREG_STAT_RXTOHOST)) &&
+	    (hp->happy_flags & HFLAG_QUATTRO) != 0 &&
+	    pci_dma_wsync != NULL)
+		(void) *(pci_dma_wsync);
+
 	if(happy_status & GREG_STAT_ERRORS) {
 		HMD(("ERRORS "));
 		if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
diff -urN linux-2.2.17-pre2/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- linux-2.2.17-pre2/drivers/sound/dmasound.c	Tue Jan  4 10:12:21 2000
+++ linux/drivers/sound/dmasound.c	Mon Dec  3 22:05:46 2001
@@ -115,6 +115,7 @@
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
+#include <asm/feature.h>
 #include "awacs_defs.h"
 #include <linux/nvram.h>
 #include <linux/vt_kern.h>
@@ -175,6 +176,7 @@
 static int awacs_rate_index;
 static int awacs_subframe;
 static int awacs_spkr_vol;
+static struct device_node* awacs_node;
 
 static int awacs_revision;
 #define AWACS_BURGUNDY	100		/* fake revision # for burgundy */
@@ -3018,6 +3020,12 @@
 	out_le32(&awacs_txdma->control, RUN<<16);
 	/* disable interrupts from awacs interface */
 	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+#ifdef CONFIG_PMAC_PBOOK
+	if (is_pbook_G3) {
+		feature_clear(awacs_node, FEATURE_Sound_power);
+		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+	}
+#endif
 	free_irq(awacs_irq, (void *) awacs);
 	free_irq(awacs_tx_irq, (void *) awacs);
 	kfree(awacs_tx_cmd_space);
@@ -3370,8 +3378,21 @@
 		PMacSilence();
 		disable_irq(awacs_irq);
 		disable_irq(awacs_tx_irq);
+		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+		feature_clear(awacs_node, FEATURE_Sound_power);
 		break;
 	case PBOOK_WAKE:
+		/* There is still a problem on wake. Sound seems to work fine
+		   if I launch mpg123 and resumes fine if mpg123 was playing,
+		   but the console beep is dead until I do something with the
+		   mixer. Probably yet another timing issue */
+		if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+		    || !feature_test(awacs_node, FEATURE_Sound_power)) {
+			/* these aren't present on the 3400 AFAIK -- paulus */
+			feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+			feature_set(awacs_node, FEATURE_Sound_power);
+			mdelay(1000);
+		}
 		out_le32(&awacs->control, MASK_IEPC
 			 | (awacs_rate_index << 8) | 0x11
 			 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
@@ -3388,6 +3409,16 @@
 			mdelay(2);
 			awacs_write(awacs_reg[1] | MASK_ADDR1);
 		}
+		/* enable CD sound input */
+		if (macio_base && is_pbook_G3) {
+			out_8(macio_base + 0x37, 3);
+		} else if (is_pbook_3400) {
+			feature_set(awacs_node, FEATURE_IOBUS_enable);
+			udelay(10);
+			in_8((unsigned char *)0xf301a190);
+		}
+ 		/* Resume pending sounds. Paul, Is this wrong ? */
+ 		PMacPlay();
 	}
 	return PBOOK_SLEEP_OK;
 }
@@ -4596,6 +4627,7 @@
 	u_long fmt;
 	int data;
 	int size, nbufs;
+	audio_buf_info info;
 
 	switch (cmd) {
 	case SNDCTL_DSP_RESET:
@@ -4671,6 +4703,14 @@
 		sq_setup(numBufs, size, sound_buffers);
 		sq.max_active = nbufs;
 		return 0;
+	case SNDCTL_DSP_GETOSPACE:
+		info.fragments = sq.max_active - sq.count;
+		info.fragstotal = sq.max_active;
+		info.fragsize = sq.block_size;
+		info.bytes = info.fragments * info.fragsize;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
 
 	default:
 		return mixer_ioctl(inode, file, cmd, arg);
@@ -4777,7 +4817,9 @@
 #endif /* CONFIG_AMIGA */
 #ifdef CONFIG_PPC
 	case DMASND_AWACS:
-		sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision);
+		/* BenH: This one used to sprintf in mach which doesn't point to
+		 * a large enough buffer */
+		len += sprintf(buffer+len, "PowerMac (AWACS rev %d) ", awacs_revision);
 		break;
 #endif /* CONFIG_PPC */
 	}
@@ -5022,6 +5064,16 @@
 			printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
 			return;
 		}
+		awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+		if (machine_is_compatible("PowerBook1,1")
+		    || machine_is_compatible("AAPL,PowerBook1998")) {
+			feature_set(np, FEATURE_Sound_CLK_enable);
+			feature_set(np, FEATURE_Sound_power);
+			/* Shorter delay will not work */
+			mdelay(1000);
+		}
+#endif
 		awacs_tx_cmds = (volatile struct dbdma_cmd *)
 			DBDMA_ALIGN(awacs_tx_cmd_space);
 		awacs_reg[0] = MASK_MUX_CD;
@@ -5041,7 +5093,10 @@
 			awacs_revision =
 				(in_le32(&awacs->codec_stat) >> 12) & 0xf;
 			if (awacs_revision == 3) {
+				mdelay(100);
 				awacs_write(0x6000);
+				mdelay(2);
+				awacs_write(awacs_reg[1] + MASK_ADDR1);
 				awacs_enable_amp(100 * 0x101);
 			}
 		}
@@ -5063,27 +5118,35 @@
 		/* Powerbooks have odd ways of enabling inputs such as
 		   an expansion-bay CD or sound from an internal modem
 		   or a PC-card modem. */
-		if (machine_is_compatible("AAPL,3400/2400")) {
+		if (machine_is_compatible("AAPL,3400/2400")
+			|| machine_is_compatible("AAPL,3500")) {
 			is_pbook_3400 = 1;
 			/*
 			 * Enable CD and PC-card sound inputs.
 			 * This is done by reading from address
 			 * f301a000, + 0x10 to enable the expansion-bay
 			 * CD sound input, + 0x80 to enable the PC-card
-			 * sound input.  The 0x100 seems to enable the
-			 * MESH and/or its SCSI bus drivers.
+			 * sound input.  The 0x100 enables the SCSI bus
+			 * terminator power.
 			 */
 			in_8((unsigned char *)0xf301a190);
-		} else if (machine_is_compatible("PowerBook1,1")) {
-			np = find_devices("mac-io");
-			if (np && np->n_addrs > 0) {
-				is_pbook_G3 = 1;
-				macio_base = (unsigned char *)
-					ioremap(np->addrs[0].address, 0x40);
-				/* enable CD sound input */
-				out_8(macio_base + 0x37, 3);
+		} else if (machine_is_compatible("PowerBook1,1")
+			   || machine_is_compatible("AAPL,PowerBook1998")) {
+			struct device_node* mio;
+			macio_base = 0;
+			is_pbook_G3 = 1;
+			for (mio = np->parent; mio; mio = mio->parent) {
+				if (strcmp(mio->name, "mac-io") == 0
+				    && mio->n_addrs > 0) {
+					macio_base = (unsigned char *) ioremap
+						(mio->addrs[0].address, 0x40);
+					break;
+				}
 			}
-		}
+			/* enable CD sound input */
+			if (macio_base)
+				out_8(macio_base + 0x37, 3);
+ 		}
 	}
 #endif /* CONFIG_PPC */
 
diff -urN linux-2.2.17-pre2/fs/ext2/namei.c linux/fs/ext2/namei.c
--- linux-2.2.17-pre2/fs/ext2/namei.c	Tue Jan  4 10:12:23 2000
+++ linux/fs/ext2/namei.c	Mon Dec  3 22:05:46 2001
@@ -418,6 +418,10 @@
 		if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
 					      EXT2_FEATURE_INCOMPAT_FILETYPE))
 			de->file_type = EXT2_FT_REG_FILE;
+	} else if (S_ISSOCK(inode->i_mode)) {
+		if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+					      EXT2_FEATURE_INCOMPAT_FILETYPE))
+			de->file_type = EXT2_FT_SOCK;
 	} else if (S_ISCHR(inode->i_mode)) {
 		inode->i_op = &chrdev_inode_operations;
 		if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
@@ -793,6 +797,8 @@
 			de->file_type = EXT2_FT_DIR;
 		else if (S_ISLNK(inode->i_mode))
 			de->file_type = EXT2_FT_SYMLINK;
+		else if (S_ISSOCK(inode->i_mode))  
+			de->file_type = EXT2_FT_SOCK;
 		else if (S_ISCHR(inode->i_mode))
 			de->file_type = EXT2_FT_CHRDEV;
 		else if (S_ISBLK(inode->i_mode))
diff -urN linux-2.2.17-pre2/fs/read_write.c linux/fs/read_write.c
--- linux-2.2.17-pre2/fs/read_write.c	Wed Jun  7 14:26:44 2000
+++ linux/fs/read_write.c	Mon Dec  3 22:05:47 2001
@@ -210,12 +210,19 @@
 	if (copy_from_user(iov, vector, count*sizeof(*vector)))
 		goto out;
 
+	/* BSD readv/writev returns EINVAL if one of the iov_len
+	   values < 0 or tot_len overflowed a 32-bit integer. -ink */
 	tot_len = 0;
-	for (i = 0 ; i < count ; i++)
-		tot_len += iov[i].iov_len;
-
-	if((long) tot_len <0)
-		return -EINVAL;
+	ret = -EINVAL;
+	for (i = 0 ; i < count ; i++) {
+		size_t tmp = tot_len;
+		int len = iov[i].iov_len;
+		if (len < 0)
+			goto out;
+		(u32)tot_len += len;
+		if (tot_len < tmp || tot_len < (u32)len)
+			goto out;
+	}
 
 	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
diff -urN linux-2.2.17-pre2/include/asm-ppc/bootx.h linux/include/asm-ppc/bootx.h
--- linux-2.2.17-pre2/include/asm-ppc/bootx.h	Wed Aug 25 17:29:49 1999
+++ linux/include/asm-ppc/bootx.h	Mon Dec  3 22:05:47 2001
@@ -133,4 +133,3 @@
 #endif
 
 #endif
-    
\ No newline at end of file
diff -urN linux-2.2.17-pre2/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- linux-2.2.17-pre2/include/asm-ppc/elf.h	Wed Sep 30 10:14:33 1998
+++ linux/include/asm-ppc/elf.h	Mon Dec  3 22:05:47 2001
@@ -5,9 +5,11 @@
  * ELF register definitions..
  */
 #include <asm/ptrace.h>
+#include <asm/types.h>
 
 #define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
 #define ELF_NFPREG	33	/* includes fpscr */
+#define ELF_NVRREG	33	/* includes vscr */
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -36,6 +38,10 @@
 
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/* Altivec registers */
+typedef vector128 elf_vrreg_t;
+typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
 
 #define ELF_CORE_COPY_REGS(gregs, regs) \
 	memcpy(gregs, regs, \
diff -urN linux-2.2.17-pre2/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h
--- linux-2.2.17-pre2/include/asm-ppc/feature.h	Wed Aug 25 17:29:49 1999
+++ linux/include/asm-ppc/feature.h	Mon Dec  3 22:05:47 2001
@@ -8,12 +8,13 @@
  * for more details.
  *
  * Copyright (C) 1998 Paul Mackerras.
+ * 
  */
 #ifndef __ASM_PPC_FEATURE_H
 #define __ASM_PPC_FEATURE_H
 
 /*
- * The FCR bits for particular features vary somewhat between
+ * The FCR selector for particular features vary somewhat between
  * different machines.  So we abstract a list of features here
  * and let the feature_* routines map them to the actual bits.
  */
@@ -25,19 +26,25 @@
 	FEATURE_Serial_IO_B,
 	FEATURE_SWIM3_enable,
 	FEATURE_MESH_enable,
-	FEATURE_IDE_enable,
-	FEATURE_VIA_enable,
-	FEATURE_CD_power,
+	FEATURE_IDE0_enable,		/* Internal IDE */
+	FEATURE_IDE0_reset,		/* Internal IDE */
+	FEATURE_IOBUS_enable,		/* Internal IDE */
 	FEATURE_Mediabay_reset,
-	FEATURE_Mediabay_enable,
+	FEATURE_Mediabay_power,
 	FEATURE_Mediabay_PCI_enable,
-	FEATURE_Mediabay_IDE_enable,
+	FEATURE_IDE1_enable,		/* MediaBay IDE */
+	FEATURE_IDE1_reset,		/* MediaBay IDE */
 	FEATURE_Mediabay_floppy_enable,
 	FEATURE_BMac_reset,
 	FEATURE_BMac_IO_enable,
-	FEATURE_Modem_Reset,
-	FEATURE_IDE_DiskPower,
-	FEATURE_IDE_Reset,
+	FEATURE_Modem_power,
+	FEATURE_Slow_SCC_PCLK,
+	FEATURE_Sound_power,
+	FEATURE_Sound_CLK_enable,
+	FEATURE_IDE2_enable,
+	FEATURE_IDE2_reset,
+	FEATURE_Mediabay_IDE_switch,	/* MB IDE bus switch */
+	FEATURE_Mediabay_content,	/* MB content indicator enable */
 	FEATURE_last,
 };
 
diff -urN linux-2.2.17-pre2/include/asm-ppc/heathrow.h linux/include/asm-ppc/heathrow.h
--- linux-2.2.17-pre2/include/asm-ppc/heathrow.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/heathrow.h	Mon Dec  3 22:05:47 2001
@@ -0,0 +1,47 @@
+/*
+ * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
+ *
+ * Grabbed from Open Firmware definitions on a PowerBook G3 Series
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ */
+
+/* offset from ohare base for feature control register */
+#define HEATHROW_FEATURE_REG	0x38
+
+/*
+ * Bits in feature control register.
+ * Bits postfixed with a _N are in inverse logic
+ */
+#define HRW_RESET_SCC		0x00000001	/* Named in_use_led in OF ??? */
+#define HRW_BAY_POWER_N		0x00000002
+#define HRW_BAY_PCI_ENABLE	0x00000004
+#define HRW_BAY_IDE_ENABLE	0x00000008
+#define HRW_BAY_FLOPPY_ENABLE	0x00000010
+#define HRW_IDE0_ENABLE		0x00000020
+#define HRW_IDE0_RESET_N	0x00000040
+#define HRW_BAY_RESET_N		0x00000080
+#define HRW_IOBUS_ENABLE	0x00000100	/* Internal IDE ? */
+#define HRW_SCC_ENABLE		0x00000200
+#define HRW_MESH_ENABLE		0x00000400
+#define HRW_SWIM_ENABLE		0x00000800
+#define HRW_SOUND_POWER_N	0x00001000
+#define HRW_SOUND_CLK_ENABLE	0x00002000
+#define HRW_SCCA_IO		0x00004000
+#define HRW_SCCB_IO		0x00008000
+#define HRW_PORT_OR_DESK_VIA_N	0x00010000	/* This one is 0 on PowerBook */
+#define HRW_PWM_MON_ID_N	0x00020000	/* ??? (0) */
+#define HRW_HOOK_MB_CNT_N	0x00040000	/* ??? (0) */
+#define HRW_SWIM_CLONE_FLOPPY	0x00080000	/* ??? (0) */
+#define HRW_AUD_RUN22		0x00100000	/* ??? (1) */
+#define HRW_SCSI_LINK_MODE	0x00200000	/* Read ??? (1) */
+#define HRW_ARB_BYPASS		0x00400000	/* ??? (0 on main, 1 on gatwick) */
+#define HRW_IDE1_RESET_N	0x00800000	/* Media bay */
+#define HRW_SLOW_SCC_PCLK	0x01000000	/* ??? (0) */
+#define HRW_MODEM_POWER_N	0x02000000	/* Used by internal modem on wallstreet */
+#define HRW_MFDC_CELL_ENABLE	0x04000000	/* ??? (0) */
+#define HRW_USE_MFDC		0x08000000	/* ??? (0) */
+#define HRW_BMAC_IO_ENABLE	0x60000000	/* two bits, not documented in OF */
+#define HRW_BMAC_RESET		0x80000000	/* not documented in OF */
+
+#define PADD_MODEM_POWER_N	0x00000001	/* modem power on paddington */
diff -urN linux-2.2.17-pre2/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- linux-2.2.17-pre2/include/asm-ppc/ide.h	Mon Aug  9 12:04:57 1999
+++ linux/include/asm-ppc/ide.h	Mon Dec  3 22:05:47 2001
@@ -63,16 +63,6 @@
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 
-#undef insw
-#define insw(port, buf, ns) 	do {				\
-	ppc_ide_md.insw((port), (buf), (ns));			\
-} while (0)
-     
-#undef outsw
-#define outsw(port, buf, ns) 	do {				\
-	ppc_ide_md.outsw((port), (buf), (ns));			\
-} while (0)
-
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
 #undef	SUPPORT_VLB_SYNC
diff -urN linux-2.2.17-pre2/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- linux-2.2.17-pre2/include/asm-ppc/io.h	Mon Aug  9 12:04:57 1999
+++ linux/include/asm-ppc/io.h	Mon Dec  3 22:05:47 2001
@@ -54,10 +54,10 @@
 
 #define insb(port, buf, ns)	_insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
 #define outsb(port, buf, ns)	_outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
-#define insw(port, buf, ns)	_insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define insl(port, buf, nl)	_insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define insw(port, buf, ns)	_insw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl)	_insl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
 
 #define inb(port)		in_8((unsigned char *)((port)+_IO_BASE))
 #define outb(val, port)		out_8((unsigned char *)((port)+_IO_BASE), (val))
diff -urN linux-2.2.17-pre2/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- linux-2.2.17-pre2/include/asm-ppc/keyboard.h	Wed May  3 17:16:50 2000
+++ linux/include/asm-ppc/keyboard.h	Mon Dec  3 22:05:47 2001
@@ -72,8 +72,7 @@
 }
 
 #define kbd_sysrq_xlate	(ppc_md.kbd_sysrq_xlate)
-
-#define SYSRQ_KEY 0x54
+#define SYSRQ_KEY (ppc_md.SYSRQ_KEY)
 
 /* resource allocation */
 #define kbd_request_region()
diff -urN linux-2.2.17-pre2/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- linux-2.2.17-pre2/include/asm-ppc/machdep.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/machdep.h	Mon Dec  3 22:05:47 2001
@@ -50,6 +50,7 @@
 	void		(*kbd_init_hw)(void);
 #ifdef CONFIG_MAGIC_SYSRQ
 	unsigned char 	*kbd_sysrq_xlate;
+	unsigned long	SYSRQ_KEY;
 #endif
 
 	/* PCI interfaces */
diff -urN linux-2.2.17-pre2/include/asm-ppc/mediabay.h linux/include/asm-ppc/mediabay.h
--- linux-2.2.17-pre2/include/asm-ppc/mediabay.h	Sun Nov 15 10:51:50 1998
+++ linux/include/asm-ppc/mediabay.h	Mon Dec  3 22:05:47 2001
@@ -7,11 +7,16 @@
 #ifndef _PPC_MEDIABAY_H
 #define _PPC_MEDIABAY_H
 
+#ifdef __KERNEL__
+
+/* We keep those constants local to the kernel to avoid
+ * compatibility problems with different HW. A /proc inteface
+ * could be defined to tell userland about the content of the bay
+ */
 #define MB_FD	0		/* media bay contains floppy drive */
+#define MB_FD1	1		/* media bay contains floppy drive */
 #define MB_CD	3		/* media bay contains ATA drive such as CD */
-#define MB_NO	7		/* media bay contains nothing */
-
-#ifdef __KERNEL__
+#define MB_NO	0xF		/* media bay contains nothing */
 
 void media_bay_init(void);
 int check_media_bay(struct device_node *which_bay, int what);
diff -urN linux-2.2.17-pre2/include/asm-ppc/nvram.h linux/include/asm-ppc/nvram.h
--- linux-2.2.17-pre2/include/asm-ppc/nvram.h	Sat Aug 16 09:51:09 1997
+++ linux/include/asm-ppc/nvram.h	Mon Dec  3 22:05:47 2001
@@ -14,13 +14,13 @@
 
 #define MOTO_RTC_SECONDS		0x1FF9
 #define MOTO_RTC_MINUTES		0x1FFA
-#define MOTO_RTC_HOURS		0x1FFB
+#define MOTO_RTC_HOURS			0x1FFB
 #define MOTO_RTC_DAY_OF_WEEK		0x1FFC
-#define MOTO_RTC_DAY_OF_MONTH	0x1FFD
-#define MOTO_RTC_MONTH		0x1FFE
-#define MOTO_RTC_YEAR		0x1FFF
-#define MOTO_RTC_CONTROLA            0x1FF8
-#define MOTO_RTC_CONTROLB            0x1FF9
+#define MOTO_RTC_DAY_OF_MONTH		0x1FFD
+#define MOTO_RTC_MONTH			0x1FFE
+#define MOTO_RTC_YEAR			0x1FFF
+#define MOTO_RTC_CONTROLA        	0x1FF8
+#define MOTO_RTC_CONTROLB        	0x1FF9
 
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
@@ -29,5 +29,31 @@
 #ifndef BIN_TO_BCD
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
+
+/* PowerMac specific nvram stuffs */
+
+enum {
+	pmac_nvram_OF,		/* Open Firmware partition */
+	pmac_nvram_XPRAM,	/* MacOS XPRAM partition */
+	pmac_nvram_NR		/* MacOS Name Registry partition */
+};
+
+/* Return partition offset in nvram */
+extern int	pmac_get_partition(int partition);
+
+/* Direct access to XPRAM */
+extern u8	pmac_xpram_read(int xpaddr);
+extern void	pmac_xpram_write(int xpaddr, u8 data);
+
+/* 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 */
+};
 
 #endif
diff -urN linux-2.2.17-pre2/include/asm-ppc/ohare.h linux/include/asm-ppc/ohare.h
--- linux-2.2.17-pre2/include/asm-ppc/ohare.h	Wed Aug 25 17:29:49 1999
+++ linux/include/asm-ppc/ohare.h	Mon Dec  3 22:05:47 2001
@@ -2,6 +2,9 @@
  * ohare.h: definitions for using the "O'Hare" I/O controller chip.
  *
  * Copyright (C) 1997 Paul Mackerras.
+ * 
+ * BenH: Changed to match those of heathrow (but not all of them). Please
+ *       check if I didn't break anything (especially the media bay).
  */
 
 /* offset from ohare base for feature control register */
@@ -13,21 +16,21 @@
  * and may differ for other machines.
  */
 #define OH_SCC_RESET		1
-#define OH_BAY_RESET		2	/* a guess */
+#define OH_BAY_POWER_N		2	/* a guess */
 #define OH_BAY_PCI_ENABLE	4	/* a guess */
 #define OH_BAY_IDE_ENABLE	8
 #define OH_BAY_FLOPPY_ENABLE	0x10
-#define OH_IDE_ENABLE		0x20
-#define OH_IDE_POWER		0x40	/* a guess */
-#define OH_BAY_ENABLE		0x80
-#define OH_IDE_RESET		0x100	/* 0-based, a guess */
+#define OH_IDE0_ENABLE		0x20
+#define OH_IDE0_RESET_N		0x40	/* a guess */
+#define OH_BAY_RESET_N		0x80
+#define OH_IOBUS_ENABLE		0x100	/* IOBUS seems to be IDE */
 #define OH_SCC_ENABLE		0x200
 #define OH_MESH_ENABLE		0x400
 #define OH_FLOPPY_ENABLE	0x800
 #define OH_SCCA_IO		0x4000
 #define OH_SCCB_IO		0x8000
-#define OH_VIA_ENABLE		0x10000
-#define OH_IDECD_POWER		0x800000
+#define OH_VIA_ENABLE		0x10000	/* Is apparently wrong, to be verified */
+#define OH_IDE1_RESET_N		0x800000
 
 /*
  * Bits to set in the feature control register on PowerBooks.
diff -urN linux-2.2.17-pre2/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- linux-2.2.17-pre2/include/asm-ppc/page.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/page.h	Mon Dec  3 22:05:47 2001
@@ -64,7 +64,7 @@
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 extern void clear_page(unsigned long page);
-#define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+extern void copy_page(unsigned long to, unsigned long from);
 
 /* map phys->virtual and virtual->phys for RAM pages */
 #ifdef CONFIG_APUS
diff -urN linux-2.2.17-pre2/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- linux-2.2.17-pre2/include/asm-ppc/pmu.h	Tue Oct 26 17:53:42 1999
+++ linux/include/asm-ppc/pmu.h	Mon Dec  3 22:05:47 2001
@@ -51,6 +51,7 @@
 	PMU_OHARE_BASED,	/* 2400, 3400, 3500 (old G3 powerbook) */
 	PMU_HEATHROW_BASED,	/* PowerBook G3 series */
 	PMU_PADDINGTON_BASED,	/* 1999 PowerBook G3 */
+	PMU_KEYLARGO_BASED,	/* Core99 motherboard (PMU99) */
 };
 
 /*
@@ -66,6 +67,8 @@
 #define PMU_IOC_SET_BACKLIGHT	_IOW('B', 2, sizeof(__u32))
 /* out param: u32*	backlight value: 0 to 31 */
 #define PMU_IOC_GET_MODEL	_IOR('B', 3, sizeof(__u32*))
+/* out param: u32*	has_adb: 0 or 1 */
+#define PMU_IOC_HAS_ADB		_IOR('B', 4, sizeof(__u32*)) 
 
 #ifdef __KERNEL__
 
diff -urN linux-2.2.17-pre2/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- linux-2.2.17-pre2/include/asm-ppc/processor.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-ppc/processor.h	Mon Dec  3 22:05:47 2001
@@ -7,6 +7,7 @@
 #include <asm/residual.h>
 
 /* Bit encodings for Machine State Register (MSR) */
+#define MSR_VEC		(1<<25)		/* Enable Altivec */
 #define MSR_POW		(1<<18)		/* Enable Power Management */
 #define MSR_TGPR	(1<<17)		/* TLB Update registers in use */
 #define MSR_ILE		(1<<16)		/* Interrupt Little-Endian enable */
@@ -53,6 +54,9 @@
 #define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
 #define HID0_SPD	(1<<9)		/* Speculative disable */
 #define HID0_SIED	(1<<7)		/* Serial Instruction Execution [Disable] */
+#define HID0_SGE	(1<<7)		/* Store Gathering Enable */
+#define HID0_BTIC	(1<<5)		/* Branch Target Instruction Cache Enable */
+#define HID0_ABE	(1<<3)		/* Address Broadcast Enable */
 #define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
 #define HID0_BTCD	(1<<1)		/* Branch target cache disable */
 
@@ -147,6 +151,7 @@
 #define EAR	282	/* External Address Register */
 #define L2CR	1017    /* PPC 750 L2 control register */
 
+#define ICTC	1019
 #define THRM1	1020
 #define THRM2	1021
 #define THRM3	1022
@@ -177,6 +182,10 @@
 #define SR15	15
 
 #ifndef __ASSEMBLY__
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+
 extern int _machine;
 
 /* Temporary hacks until we can clean things up better - Corey */
@@ -242,10 +251,21 @@
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
 	unsigned long	fpscr;		/* Floating point status */
+#ifdef CONFIG_ALTIVEC
+	vector128	vr[32];		/* Complete AltiVec set */
+	vector128	vscr;		/* AltiVec status */
+	unsigned long	vrsave;
+#endif /* CONFIG_ALTIVEC */
 };
 
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
 
+#ifdef CONFIG_ALTIVEC
+#define INIT_TSS_AVEC	{{{0}}}, {{0}}, 0,
+#else
+#define INIT_TSS_AVEC
+#endif /* CONFIG_ALTIVEC */
+
 #define INIT_TSS  { \
 	INIT_SP, /* ksp */ \
 	(unsigned long *) swapper_pg_dir, /* pg_tables */ \
@@ -253,7 +273,8 @@
 	(struct pt_regs *)INIT_SP - 1, /* regs */ \
 	KERNEL_DS, /*fs*/ \
 	0, /* last_syscall */ \
-	{0}, 0, 0 \
+	{0}, 0, 0, \
+	INIT_TSS_AVEC \
 }
 
 /*
@@ -295,5 +316,6 @@
 
 #endif /* ndef ASSEMBLY*/
 
-  
+#endif /* __KERNEL__ */
+
 #endif /* __ASM_PPC_PROCESSOR_H */
diff -urN linux-2.2.17-pre2/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h
--- linux-2.2.17-pre2/include/asm-ppc/prom.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-ppc/prom.h	Mon Dec  3 22:05:47 2001
@@ -72,7 +72,10 @@
 extern struct device_node *find_path_device(const char *path);
 extern struct device_node *find_compatible_devices(const char *type,
 						   const char *compat);
+extern struct device_node *find_pci_device_OFnode(unsigned char bus,
+	unsigned char dev_fn);
 extern struct device_node *find_phandle(phandle);
+extern struct device_node *find_all_nodes(void);
 extern int device_is_compatible(struct device_node *device, const char *);
 extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
diff -urN linux-2.2.17-pre2/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- linux-2.2.17-pre2/include/asm-ppc/system.h	Fri Jun  4 13:30:47 1999
+++ linux/include/asm-ppc/system.h	Mon Dec  3 22:05:47 2001
@@ -72,6 +72,7 @@
 extern void pmac_find_display(void);
 extern void giveup_fpu(struct task_struct *);
 extern void enable_kernel_fp(void);
+extern void giveup_altivec(struct task_struct *);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int call_rtas(const char *, int, int, unsigned long *, ...);
diff -urN linux-2.2.17-pre2/include/asm-ppc/termbits.h linux/include/asm-ppc/termbits.h
--- linux-2.2.17-pre2/include/asm-ppc/termbits.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/termbits.h	Mon Dec  3 22:05:47 2001
@@ -57,12 +57,9 @@
 #define ICRNL	0000400
 #define IXON	0001000
 #define IXOFF	0002000
-#if defined(__KERNEL__) || defined(__USE_BSD)
-  /* POSIX.1 doesn't want these... */
-# define IXANY		0004000
-# define IUCLC		0010000
-# define IMAXBEL	0020000
-#endif
+#define IXANY	0004000
+#define IUCLC	0010000
+#define IMAXBEL	0020000
 
 /* c_oflag bits */
 #define OPOST	0000001
diff -urN linux-2.2.17-pre2/include/asm-ppc/types.h linux/include/asm-ppc/types.h
--- linux-2.2.17-pre2/include/asm-ppc/types.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/types.h	Mon Dec  3 22:05:47 2001
@@ -39,6 +39,10 @@
 typedef signed long long s64;
 typedef unsigned long long u64;
 
+typedef struct {
+	u32 u[4];
+} __attribute((aligned(16))) vector128;
+
 #define BITS_PER_LONG 32
 
 #endif /* __KERNEL__ */
diff -urN linux-2.2.17-pre2/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h
--- linux-2.2.17-pre2/include/asm-sparc64/pbm.h	Mon Mar 15 16:10:44 1999
+++ linux/include/asm-sparc64/pbm.h	Mon Dec  3 22:05:47 2001
@@ -14,6 +14,8 @@
 
 struct linux_pbm_info;
 
+extern volatile u64 *pci_dma_wsync;
+
 /* This is what we use to determine what the PROM has assigned so
  * far, so that we can perform assignments for addresses which
  * were not taken care of by OBP.  See psycho.c for details.
diff -urN linux-2.2.17-pre2/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux-2.2.17-pre2/net/ipv4/tcp.c	Wed Jun  7 14:26:44 2000
+++ linux/net/ipv4/tcp.c	Mon Dec  3 22:05:47 2001
@@ -698,13 +698,16 @@
 
 /*
  *	Wait for more memory for a socket
+ *
+ *	If we got here an allocation has failed on us. We cannot
+ *	spin here or we may block the very code freeing memory
+ *	for us.
  */
 static void wait_for_tcp_memory(struct sock * sk)
 {
 	release_sock(sk);
 	if (!tcp_memory_free(sk)) {
 		struct wait_queue wait = { current, NULL };
-
 		sk->socket->flags &= ~SO_NOSPACE;
 		add_wait_queue(sk->sleep, &wait);
 		for (;;) {
@@ -721,6 +724,12 @@
 		}
 		current->state = TASK_RUNNING;
 		remove_wait_queue(sk->sleep, &wait);
+	}
+	else
+	{
+		/* Yield time to the memory freeing paths */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
 	}
 	lock_sock(sk);
 }
