#!/bin/sh
# this is part 05 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 05; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 		.word	_arm6_7_flush_tlb_all		@ 44
X 		.word	_arm6_7_flush_tlb_area		@ 48
X 		.word	_arm7_set_pmd			@ 52
-		.word	_arm6_7_reset			@ 56
-		.word	_arm6_7_flush_cache		@ 60
-
+		.word	_arm6_7_set_pte			@ 56
+		.word	_arm6_7_reset			@ 60
X 		.word	_arm6_7_flush_cache		@ 64
+
X 		.word	_arm6_7_flush_cache		@ 68
+		.word	_arm6_7_flush_cache		@ 72
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.2.7/linux/arch/arm/mm/proc-sa110.S	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/proc-sa110.S	Sat May  8 11:07:16 1999
@@ -8,6 +8,7 @@
X  */
X #include <linux/linkage.h>
X #include <asm/assembler.h>
+#include <asm/hardware.h>
X #include "../lib/constants.h"
X 
X /* This is the maximum size of an area which will be flushed.  If the area
@@ -21,7 +22,6 @@
X 
X /*
X  * Function: sa110_flush_cache_all (void)
- *
X  * Purpose : Flush all cache lines
X  */
X 		.align	5
@@ -33,7 +33,7 @@
X 		ands	r1, r1, #1
X 		eor	r1, r1, #1
X 		str	r1, [r3]
-		ldr	ip, =0xdf000000
+		ldr	ip, =FLUSH_BASE
X 		addne	ip, ip, #32768
X 		add	r1, ip, #16384			@ only necessary for 16k
X 1:		ldr	r3, [ip], #32
@@ -47,11 +47,9 @@
X 
X /*
X  * Function: sa110_flush_cache_area (unsigned long address, int end, int flags)
- *
X  * Params  : address	Area start address
X  *	   : end	Area end address
X  *	   : flags	b0 = I cache as well
- *
X  * Purpose : clean & flush all cache lines associated with this area of memory
X  */
X 		.align	5
@@ -74,10 +72,8 @@
X 
X /*
X  * Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
- *
X  * Params  : address	Area start address
X  *	   : end	Area end address
- *
X  * Purpose : ensure all dirty cachelines in the specified area have been
X  *	     written out to memory (for DMA)
X  */
@@ -99,13 +95,10 @@
X 
X /*
X  * Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
- *
X  * Params  : address	Area start address
X  *	   : end	Area end address
- *
X  * Purpose : throw away all D-cached data in specified region without
- *	     an obligation to write it ack.
- *
+ *	     an obligation to write it back.
X  * Note    : Must clean the D-cached entries around the boundaries if the
X  *	     start and/or end address are not cache aligned.
X  */
@@ -124,9 +117,7 @@
X 
X /*
X  * Function: sa110_flush_cache_entry (unsigned long address)
- *
X  * Params  : address	Address of cache line to flush
- *
X  * Purpose : clean & flush an entry
X  */
X 		.align	5
@@ -138,24 +129,23 @@
X 		mov	pc, lr
X 
X /*
- * Function: sa110_flush_cache_pte (unsigned long address)
- *
+ * Function: sa110_clean_cache_area(unsigned long start, unsigned long size)
X  * Params  : address	Address of cache line to clean
- *
X  * Purpose : Ensure that physical memory reflects cache at this location
X  *	     for page table purposes.
X  */
-_sa110_flush_cache_pte:
-		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+_sa110_clean_cache_area:
+1:		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+		add	r0, r0, #32
+		subs	r1, r1, #32
+		bhi	1b
X 		mov	pc, lr
X 
X /*
X  * Function: sa110_flush_ram_page (unsigned long page)
- *
X  * Params  : address	Area start address
X  *	   : size	size of area
X  *	   : flags	b0 = I cache as well
- *
X  * Purpose : clean & flush all cache lines associated with this area of memory
X  */
X 		.align	5
@@ -176,7 +166,6 @@
X 
X /*
X  * Function: sa110_flush_tlb_all (void)
- *
X  * Purpose : flush all TLB entries in all caches
X  */
X 		.align	5
@@ -188,11 +177,9 @@
X 
X /*
X  * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags)
- *
X  * Params  : address	Area start address
X  *	   : end	Area end address
X  *	   : flags	b0 = I cache as well
- *
X  * Purpose : flush a TLB entry
X  */
X 		.align	5
@@ -212,22 +199,21 @@
X 
X 		.align	5
X _sa110_flush_icache_area:
-		mov	r3, #0
X 1:		mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
X 		add	r0, r0, #32
-		cmp	r0, r1
-		blt	1b
+		subs	r1, r1, #32
+		bhi	1b
+		mov	r0, #0
+		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
X 		mcr	p15, 0, r0, c7, c5, 0		@ flush I cache
X 		mov	pc, lr
X /*
X  * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
- *
X  * Params  : prev	Old task structure
X  *	   : next	New task structure for process to run
- *
+ * Returns : prev
X  * Purpose : Perform a task switch, saving the old processes state, and restoring
X  *	     the new.
- *
X  * Notes   : We don't fiddle with the FP registers here - we postpone this until
X  *	     the new task actually uses FP.  This way, we don't swap FP for tasks
X  *	     that do not require it.
@@ -237,20 +223,30 @@
X 		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
X 		mrs	ip, cpsr
X 		stmfd	sp!, {ip}			@ Save cpsr_SVC
+		ldr	r2, [r0, #TSS_MEMMAP]		@ Get old page tables
X 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
X 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r0, [r1, #TSK_ADDR_LIMIT]
-		teq	r0, #0
-		moveq	r0, #DOM_KERNELDOMAIN
-		movne	r0, #DOM_USERDOMAIN
-		mcr	p15, 0, r0, c3, c0		@ Set segment
-		ldr	r0, [r1, #TSS_MEMMAP]		@ Page table pointer
+		ldr	r4, [r1, #TSK_ADDR_LIMIT]
+		teq	r4, #0
+		moveq	r4, #DOM_KERNELDOMAIN
+		movne	r4, #DOM_USERDOMAIN
+		mcr	p15, 0, r4, c3, c0		@ Set segment
+		ldr	r4, [r1, #TSS_MEMMAP]		@ Page table pointer
+/*
+ * Flushing the cache is nightmarishly slow, so we take any excuse
+ * to get out of it.  If the old page table is the same as the new,
+ * this is a CLONE_VM relative of the old task and there is no need
+ * to flush.  The overhead of the tests isn't even on the radar
+ * compared to the cost of the flush itself.
+ */
+		teq	r4, r2
+		beq	2f
X 		ldr	r3, =Lclean_switch
X 		ldr	r2, [r3]
X 		ands	r2, r2, #1
X 		eor	r2, r2, #1
X 		str	r2, [r3]
-		ldr	r2, =0xdf000000
+		ldr	r2, =FLUSH_BASE
X 		addne	r2, r2, #32768
X 		add	r1, r2, #16384			@ only necessary for 16k
X 1:		ldr	r3, [r2], #32
@@ -259,19 +255,16 @@
X 		mov	r1, #0
X 		mcr	p15, 0, r1, c7, c5, 0		@ flush I cache
X 		mcr	p15, 0, r1, c7, c10, 4		@ drain WB
-		mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
+		mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
X 		mcr	p15, 0, r1, c8, c7, 0		@ flush TLBs
-		ldmfd	sp!, {ip}
+2:		ldmfd	sp!, {ip}
X 		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
X 		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
X 
X /*
X  * Function: sa110_data_abort ()
- *
X  * Params  : r0 = address of aborted instruction
- *
X  * Purpose : obtain information about current aborted instruction
- *
X  * Returns : r0 = address of abort
X  *	   : r1 = FSR
X  *	   : r2 != 0 if writing
@@ -288,12 +281,10 @@
X 		mov	pc, lr
X 
X /*
- * Function: sa110_set_pmd ()
- *
+ * Function: sa110_set_pmd(pmd_t *pmdp, pmd_t pmd)
X  * Params  : r0 = Address to set
X  *	   : r1 = value to set
- *
- * Purpose : Set a PMD and flush it out of any WB cache
+ * Purpose : Set a PMD and flush it out
X  */
X 		.align	5
X _sa110_set_pmd:	str	r1, [r0]
@@ -301,23 +292,51 @@
X 		mov	pc, lr
X 
X /*
+ * Function: sa110_set_pte(pte_t *ptep, pte_t pte)
+ * Params  : r0 = Address to set
+ *	   : r1 = value to set
+ * Purpose : Set a PTE and flush it out
+ */
+		.align	5
+_sa110_set_pte:	str	r1, [r0], #-1024		@ linux version
+
+		eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
+
+		bic	r2, r1, #0xff0
+		bic	r2, r2, #3
+		orr	r2, r2, #HPTE_TYPE_SMALL
+
+		tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
+		orrne	r2, r2, #HPTE_AP_READ
+
+		tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+		orreq	r2, r2, #HPTE_AP_WRITE
+
+		tst	r1, #LPTE_PRESENT | LPTE_YOUNG	@ Present and Young?
+		movne	r2, #0
+
+		str	r2, [r0]			@ hardware version
+		mov	r0, r0
+		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+		mov	pc, lr
+
+/*
X  * Function: sa110_check_bugs (void)
X  *	   : sa110_proc_init (void)
X  *	   : sa110_proc_fin (void)
- *
X  * Notes   : This processor does not require these
X  */
X _sa110_check_bugs:
X 		mrs	ip, cpsr
X 		bic	ip, ip, #F_BIT
X 		msr	cpsr, ip
+
X _sa110_proc_init:
X _sa110_proc_fin:
X 		mov	pc, lr
X 
X /*
X  * Function: sa110_reset
- *
X  * Notes   : This sets up everything for a reset
X  */
X _sa110_reset:	mrs	r1, cpsr
@@ -350,14 +369,15 @@
X 		.word	_sa110_flush_cache_all		@ 24
X 		.word	_sa110_flush_cache_area		@ 28
X 		.word	_sa110_flush_cache_entry	@ 32
-		.word	_sa110_flush_cache_pte		@ 36
+		.word	_sa110_clean_cache_area		@ 36
X 		.word	_sa110_flush_ram_page		@ 40
X 		.word	_sa110_flush_tlb_all		@ 44
X 		.word	_sa110_flush_tlb_area		@ 48
X 
X 		.word	_sa110_set_pmd			@ 52
-		.word	_sa110_reset			@ 56
-		.word	_sa110_flush_icache_area	@ 60
+		.word	_sa110_set_pte			@ 56
+		.word	_sa110_reset			@ 60
+		.word	_sa110_flush_icache_area	@ 64
X 
-		.word	_sa110_cache_wback_area		@ 64
-		.word	_sa110_cache_purge_area		@ 68
+		.word	_sa110_cache_wback_area		@ 68
+		.word	_sa110_cache_purge_area		@ 72
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/small_page.c linux/arch/arm/mm/small_page.c
--- v2.2.7/linux/arch/arm/mm/small_page.c	Wed Sep  9 14:51:05 1998
+++ linux/arch/arm/mm/small_page.c	Sat May  8 11:06:57 1999
@@ -5,6 +5,8 @@
X  *
X  * Changelog:
X  *  26/01/1996	RMK	Cleaned up various areas to make little more generic
+ *  07/02/1999	RMK	Support added for 16K and 32K page sizes
+ *			containing 8K blocks
X  */
X 
X #include <linux/signal.h>
@@ -19,21 +21,32 @@
X #include <linux/swap.h>
X #include <linux/smp.h>
X 
-#define SMALL_ALLOC_SHIFT	(10)
+#if PAGE_SIZE == 4096
+/* 2K blocks */
+#define SMALL_ALLOC_SHIFT	(11)
+#define NAME(x)			x##_2k
+#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384
+/* 8K blocks */
+#define SMALL_ALLOC_SHIFT	(13)
+#define NAME(x)			x##_8k
+#endif
+
X #define SMALL_ALLOC_SIZE	(1 << SMALL_ALLOC_SHIFT)
X #define NR_BLOCKS		(PAGE_SIZE / SMALL_ALLOC_SIZE)
+#define BLOCK_MASK		((1 << NR_BLOCKS) - 1)
X 
-#if NR_BLOCKS != 4
-#error I only support 4 blocks per page!
-#endif
-
-#define USED(pg)		((atomic_read(&(pg)->count) >> 8) & 15)
+#define USED(pg)		((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK)
X #define SET_USED(pg,off)	(atomic_read(&(pg)->count) |= 256 << off)
X #define CLEAR_USED(pg,off)	(atomic_read(&(pg)->count) &= ~(256 << off))
+#define ALL_USED		BLOCK_MASK
X #define IS_FREE(pg,off)		(!(atomic_read(&(pg)->count) & (256 << off)))
-#define PAGE_PTR(page,block)	((struct free_small_page *)((page) + \
+#define SM_PAGE_PTR(page,block)	((struct free_small_page *)((page) + \
X 					((block) << SMALL_ALLOC_SHIFT)))
X 
+#if NR_BLOCKS != 2 && NR_BLOCKS != 4
+#error I only support 2 or 4 blocks per page
+#endif
+
X struct free_small_page {
X 	unsigned long next;
X 	unsigned long prev;
@@ -52,6 +65,7 @@
X 	1,	/* 0001 */
X 	0,	/* 0010 */
X 	2,	/* 0011 */
+#if NR_BLOCKS == 4
X 	0,	/* 0100 */
X 	1,	/* 0101 */
X 	0,	/* 0110 */
@@ -64,6 +78,7 @@
X 	1,	/* 1101 */
X 	0,	/* 1110 */
X 	4	/* 1111 */
+#endif
X };
X 
X static inline void clear_page_links(unsigned long page)
@@ -72,7 +87,7 @@
X 	int i;
X 
X 	for (i = 0; i < NR_BLOCKS; i++) {
-		fsp = PAGE_PTR(page, i);
+		fsp = SM_PAGE_PTR(page, i);
X 		fsp->next = fsp->prev = 0;
X 	}
X }
@@ -90,7 +105,7 @@
X 	for (i = 0; i < NR_BLOCKS; i++) {
X 		if (mask & (1 << i))
X 			continue;
-		fsp = PAGE_PTR(page, i);
+		fsp = SM_PAGE_PTR(page, i);
X 		fsp->prev = prev;
X 	}
X }
@@ -108,12 +123,12 @@
X 	for (i = 0; i < NR_BLOCKS; i++) {
X 		if (mask & (1 << i))
X 			continue;
-		fsp = PAGE_PTR(page, i);
+		fsp = SM_PAGE_PTR(page, i);
X 		fsp->next = next;
X 	}
X }
X 
-unsigned long get_small_page(int priority)
+unsigned long NAME(get_page)(int priority)
X {
X 	struct free_small_page *fsp;
X 	unsigned long new_page;
@@ -129,8 +144,8 @@
X 	page = mem_map + MAP_NR(small_page_ptr);
X 	offset = offsets[USED(page)];
X 	SET_USED(page, offset);
-	new_page = (unsigned long)PAGE_PTR(small_page_ptr, offset);
-	if (USED(page) == 15) {
+	new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset);
+	if (USED(page) == ALL_USED) {
X 		fsp = (struct free_small_page *)new_page;
X 		set_page_links_prev (fsp->next, 0);
X 		small_page_ptr = fsp->next;
@@ -156,30 +171,31 @@
X 	goto again;
X }
X 
-void free_small_page(unsigned long spage)
+void NAME(free_page)(unsigned long spage)
X {
X 	struct free_small_page *ofsp, *cfsp;
X 	unsigned long flags;
X 	struct page *page;
X 	int offset, oldoffset;
X 
+	if (!spage)
+		goto none;
+
X 	offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
X 	spage -= offset << SMALL_ALLOC_SHIFT;
X 
X 	page = mem_map + MAP_NR(spage);
-	if (!PageReserved(page) || !USED(page)) {
-		printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
-		return;
-	}
-	if (IS_FREE(page, offset)) {
-		printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
-		return;
-	}
+	if (!PageReserved(page) || !USED(page))
+		goto non_small;
+
+	if (IS_FREE(page, offset))
+		goto free;
+
X 	save_flags_cli (flags);
X 	oldoffset = offsets[USED(page)];
X 	CLEAR_USED(page, offset);
-	ofsp = PAGE_PTR(spage, oldoffset);
-	cfsp = PAGE_PTR(spage, offset);
+	ofsp = SM_PAGE_PTR(spage, oldoffset);
+	cfsp = SM_PAGE_PTR(spage, offset);
X 
X 	if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */
X 		cfsp->prev = 0;
@@ -197,4 +213,13 @@
X 	} else
X 		*cfsp = *ofsp;
X 	restore_flags(flags);
+	return;
+
+non_small:
+	printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
+	return;
+free:
+	printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
+none:
+	return;
X }
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.2.7/linux/arch/i386/kernel/entry.S	Wed Jan 20 23:14:04 1999
+++ linux/arch/i386/kernel/entry.S	Fri Apr 30 08:13:37 1999
@@ -154,7 +154,9 @@
X 	.globl	ret_from_fork
X ret_from_fork:
X #ifdef __SMP__
+	pushl %ebx
X 	call SYMBOL_NAME(schedule_tail)
+	addl $4, %esp
X #endif /* __SMP__ */
X 	GET_CURRENT(%ebx)
X 	jmp	ret_from_sys_call
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.2.7/linux/arch/i386/kernel/i386_ksyms.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/i386_ksyms.c	Mon May 10 10:32:45 1999
@@ -39,6 +39,7 @@
X EXPORT_SYMBOL(local_irq_count);
X EXPORT_SYMBOL(enable_irq);
X EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
X EXPORT_SYMBOL(kernel_thread);
X 
X EXPORT_SYMBOL_NOVERS(__down_failed);
@@ -91,7 +92,7 @@
X EXPORT_SYMBOL(__global_sti);
X EXPORT_SYMBOL(__global_save_flags);
X EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(mtrr_hook);
+EXPORT_SYMBOL(smp_call_function);
X #endif
X 
X #ifdef CONFIG_MCA
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.2.7/linux/arch/i386/kernel/io_apic.c	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/io_apic.c	Thu May  6 16:07:03 1999
@@ -1049,7 +1049,7 @@
X 	 * and do not need to be masked.
X 	 */
X 	ack_APIC_irq();
-	status = desc->status & ~IRQ_REPLAY;
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
X 	status |= IRQ_PENDING;
X 
X 	/*
@@ -1060,8 +1060,9 @@
X 	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
X 		action = desc->action;
X 		status &= ~IRQ_PENDING;
+		status |= IRQ_INPROGRESS;
X 	}
-	desc->status = status | IRQ_INPROGRESS;
+	desc->status = status;
X 	spin_unlock(&irq_controller_lock);
X 
X 	/*
@@ -1103,7 +1104,7 @@
X 	 * So this all has to be within the spinlock.
X 	 */
X 	mask_IO_APIC_irq(irq);
-	status = desc->status & ~IRQ_REPLAY;
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
X 
X 	/*
X 	 * If the IRQ is disabled for whatever reason, we must
@@ -1112,8 +1113,9 @@
X 	action = NULL;
X 	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
X 		action = desc->action;
+		status |= IRQ_INPROGRESS;
X 	}
-	desc->status = status | IRQ_INPROGRESS;
+	desc->status = status;
X 
X 	ack_APIC_irq();
X 	spin_unlock(&irq_controller_lock);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.2.7/linux/arch/i386/kernel/irq.c	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/irq.c	Mon May 10 10:32:45 1999
@@ -203,7 +203,7 @@
X 
X void make_8259A_irq(unsigned int irq)
X {
-	disable_irq(irq);
+	disable_irq_nosync(irq);
X 	io_apic_irqs &= ~(1<<irq);
X 	irq_desc[irq].handler = &i8259A_irq_type;
X 	enable_irq(irq);
@@ -239,11 +239,13 @@
X 	{
X 		unsigned int status;
X 		mask_and_ack_8259A(irq);
-		status = desc->status & ~IRQ_REPLAY;
+		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
X 		action = NULL;
-		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
X 			action = desc->action;
-		desc->status = status | IRQ_INPROGRESS;
+			status |= IRQ_INPROGRESS;
+		}
+		desc->status = status;
X 	}
X 	spin_unlock(&irq_controller_lock);
X 
@@ -320,7 +322,7 @@
X BUILD_SMP_INTERRUPT(reschedule_interrupt)
X BUILD_SMP_INTERRUPT(invalidate_interrupt)
X BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
-BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(call_function_interrupt)
X BUILD_SMP_INTERRUPT(spurious_interrupt)
X 
X /*
@@ -747,7 +749,7 @@
X  * hardware disable after having gotten the irq
X  * controller lock. 
X  */
-void disable_irq(unsigned int irq)
+void disable_irq_nosync(unsigned int irq)
X {
X 	unsigned long flags;
X 
@@ -757,9 +759,21 @@
X 		irq_desc[irq].handler->disable(irq);
X 	}
X 	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+/*
+ * Synchronous version of the above, making sure the IRQ is
+ * no longer running on any other IRQ..
+ */
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
X 
-	if (irq_desc[irq].status & IRQ_INPROGRESS)
-		synchronize_irq();
+	if (!local_irq_count[smp_processor_id()]) {
+		do {
+			barrier();
+		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+	}
X }
X 
X void enable_irq(unsigned int irq)
@@ -769,7 +783,7 @@
X 	spin_lock_irqsave(&irq_controller_lock, flags);
X 	switch (irq_desc[irq].depth) {
X 	case 1:
-		irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+		irq_desc[irq].status &= ~IRQ_DISABLED;
X 		irq_desc[irq].handler->enable(irq);
X 		/* fall throught */
X 	default:
@@ -864,7 +878,7 @@
X 
X 	if (!shared) {
X 		irq_desc[irq].depth = 0;
-		irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+		irq_desc[irq].status &= ~IRQ_DISABLED;
X 		irq_desc[irq].handler->startup(irq);
X 	}
X 	spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -936,7 +950,7 @@
X  *
X  * This depends on the fact that any interrupt that
X  * comes in on to an unassigned handler will get stuck
- * with "IRQ_INPROGRESS" asserted and the interrupt
+ * with "IRQ_WAITING" cleared and the interrupt
X  * disabled.
X  */
X unsigned long probe_irq_on(void)
@@ -950,8 +964,7 @@
X 	spin_lock_irq(&irq_controller_lock);
X 	for (i = NR_IRQS-1; i > 0; i--) {
X 		if (!irq_desc[i].action) {
-			unsigned int status = irq_desc[i].status | IRQ_AUTODETECT;
-			irq_desc[i].status = status & ~IRQ_INPROGRESS;
+			irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
X 			irq_desc[i].handler->startup(i);
X 		}
X 	}
@@ -974,7 +987,7 @@
X 			continue;
X 		
X 		/* It triggered already - consider it spurious. */
-		if (status & IRQ_INPROGRESS) {
+		if (!(status & IRQ_WAITING)) {
X 			irq_desc[i].status = status & ~IRQ_AUTODETECT;
X 			irq_desc[i].handler->shutdown(i);
X 		}
@@ -1000,7 +1013,7 @@
X 		if (!(status & IRQ_AUTODETECT))
X 			continue;
X 
-		if (status & IRQ_INPROGRESS) {
+		if (!(status & IRQ_WAITING)) {
X 			if (!nr_irqs)
X 				irq_found = i;
X 			nr_irqs++;
@@ -1081,8 +1094,8 @@
X 	/* self generated IPI for local APIC timer */
X 	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
X 
-	/* IPI for MTRR control */
-	set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
+	/* IPI for generic function call */
+	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
X 
X 	/* IPI vector for APIC spurious interrupts */
X 	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.2.7/linux/arch/i386/kernel/irq.h	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/irq.h	Tue May 11 10:37:06 1999
@@ -26,6 +26,7 @@
X #define IRQ_PENDING	4	/* IRQ pending - replay on enable */
X #define IRQ_REPLAY	8	/* IRQ has been replayed but not acked yet */
X #define IRQ_AUTODETECT	16	/* IRQ is being autodetected */
+#define IRQ_WAITING	32	/* IRQ not yet seen - for autodetection */
X 
X /*
X  * This is the "IRQ descriptor", which contains various information
@@ -64,7 +65,7 @@
X #define INVALIDATE_TLB_VECTOR	0x31
X #define STOP_CPU_VECTOR		0x40
X #define LOCAL_TIMER_VECTOR	0x41
-#define MTRR_CHANGE_VECTOR	0x50
+#define CALL_FUNCTION_VECTOR	0x50
X 
X /*
X  * First APIC vector available to drivers: (vectors 0x51-0xfe)
@@ -98,7 +99,6 @@
X extern int i8259A_irq_pending(unsigned int irq);
X extern void ack_APIC_irq(void);
X extern void FASTCALL(send_IPI_self(int vector));
-extern void smp_send_mtrr(void);
X extern void init_VISWS_APIC_irqs(void);
X extern void setup_IO_APIC(void);
X extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.2.7/linux/arch/i386/kernel/mca.c	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/mca.c	Mon May 10 13:00:10 1999
@@ -92,7 +92,7 @@
X  * is set to zero.
X  */
X 
-static struct MCA_info* mca_info = 0;
+static struct MCA_info* mca_info = NULL;
X 
X /* MCA registers */
X 
@@ -160,7 +160,10 @@
X 
X 		/* id = 0x0000 usually indicates hardware failure,
X 		 * however, ZP Gu (z...@castle.net> reports that his 9556
-		 * has 0x0000 as id and everything still works.
+		 * has 0x0000 as id and everything still works. There
+		 * also seem to be an adapter with id = 0x0000; the
+		 * NCR Parallel Bus Memory Card. Until this is confirmed,
+		 * however, this code will stay.
X 		 */
X 
X 		mca_info->slot[slot].status = MCA_ADAPTER_ERROR;
@@ -222,7 +225,13 @@
X 
X 	/* Allocate MCA_info structure (at address divisible by 8) */
X 
-	mca_info = kmalloc(sizeof(struct MCA_info), GFP_ATOMIC);
+	mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
+
+	if(mca_info == NULL) {
+		printk("Failed to allocate memory for mca_info!");
+		restore_flags(flags);
+		return;
+	}
X 
X 	/* Make sure adapter setup is off */
X 
@@ -382,7 +391,7 @@
X 
X int mca_find_adapter(int id, int start)
X {
-	if(mca_info == 0 || id == 0 || id == 0xffff) {
+	if(mca_info == NULL || id == 0xffff) {
X 		return MCA_NOTFOUND;
X 	}
X 
@@ -412,7 +421,7 @@
X 
X int mca_find_unused_adapter(int id, int start) 
X {
-	if(mca_info == 0 || id == 0 || id == 0xffff) {
+	if(mca_info == NULL || id == 0xffff) {
X 		return MCA_NOTFOUND;
X 	}
X 
@@ -443,7 +452,7 @@
X 
X unsigned char mca_read_stored_pos(int slot, int reg) 
X {
-	if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0) return 0;
+	if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
X 	if(reg < 0 || reg >= 8) return 0;
X 	return mca_info->slot[slot].pos[reg];
X } /* mca_read_stored_pos() */
@@ -455,7 +464,7 @@
X 	unsigned int byte = 0;
X 	unsigned long flags;
X 
-	if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0) return 0;
+	if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
X 	if(reg < 0 || reg >= 8) return 0;
X 
X 	save_flags(flags);
@@ -527,7 +536,7 @@
X 		return;
X 	if(reg < 0 || reg >= 8)
X 		return;
-	if(mca_info == 0)
+	if(mca_info == NULL)
X 		return;
X 
X 	save_flags(flags);
@@ -554,7 +563,7 @@
X 
X void mca_set_adapter_name(int slot, char* name) 
X {
-	if(mca_info == 0) return;
+	if(mca_info == NULL) return;
X 
X 	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
X 		if(name != NULL) {
@@ -570,7 +579,7 @@
X 
X void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev)
X {
-	if(mca_info == 0) return;
+	if(mca_info == NULL) return;
X 
X 	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
X 		mca_info->slot[slot].procfn = procfn;
@@ -597,7 +606,7 @@
X  
X char *mca_get_adapter_name(int slot) 
X {
-	if(mca_info == 0) return 0;
+	if(mca_info == NULL) return 0;
X 
X 	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
X 		return mca_info->slot[slot].name;
@@ -608,7 +617,7 @@
X 
X int mca_isadapter(int slot)
X {
-	if(mca_info == 0) return 0;
+	if(mca_info == NULL) return 0;
X 
X 	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
X 		return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL)
@@ -620,7 +629,7 @@
X 
X int mca_isenabled(int slot)
X {
-	if(mca_info == 0) return 0;
+	if(mca_info == NULL) return 0;
X 
X 	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
X 		return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL);
@@ -637,7 +646,7 @@
X {
X 	int i, j, len = 0;
X 
-	if(MCA_bus && mca_info != 0) 
+	if(MCA_bus && mca_info != NULL) 
X 	{
X 		/* Format POS registers of eight MCA slots */
X 
@@ -676,10 +685,10 @@
X 
X __initfunc(void mca_do_proc_init(void))
X {
-	int i = 0;
-	struct proc_dir_entry* node = 0;
+	int i;
+	struct proc_dir_entry* node = NULL;
X 
-	if(mca_info == 0) return;	/* Should never happen */
+	if(mca_info == NULL) return;	/* Should never happen */
X 
X 	proc_register(&proc_mca, &(struct proc_dir_entry) {
X 		PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO,
@@ -696,8 +705,12 @@
X 		mca_info->slot[i].dev = 0;
X 
X 		if(!mca_isadapter(i)) continue;
-		node = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
+		node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
X 
+		if(node == NULL) {
+			printk("Failed to allocate memory for MCA proc-entries!");
+			return;
+		}
X 		if(i < MCA_MAX_SLOT_NR) {
X 			node->low_ino = PROC_MCA_SLOT + i;
X 			node->namelen = sprintf(mca_info->slot[i].procname,
@@ -727,7 +740,7 @@
X 
X 	/* This really shouldn't happen... */
X 
-	if(mca_info == 0) {
+	if(mca_info == NULL) {
X 		*buf = 0;
X 		return 0;
X 	}
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.2.7/linux/arch/i386/kernel/mtrr.c	Mon Dec 28 15:00:52 1998
+++ linux/arch/i386/kernel/mtrr.c	Mon May 10 10:32:45 1999
@@ -132,6 +132,70 @@
X 	       Fixed harmless compiler warning in include/asm-i386/mtrr.h
X 	       Fixed version numbering and history for v1.23 -> v1.24.
X   v1.26
+    19990118   Richard Gooch <rgo...@atnf.csiro.au>
+	       PLACEHOLDER.
+  v1.27
+    19990123   Richard Gooch <rgo...@atnf.csiro.au>
+	       Changed locking to spin with reschedule.
+	       Made use of new <smp_call_function>.
+  v1.28
+    19990201   Zoltan Boszormenyi <zbo...@mol.hu>
+	       Extended the driver to be able to use Cyrix style ARRs.
+    19990204   Richard Gooch <rgo...@atnf.csiro.au>
+	       Restructured Cyrix support.
+  v1.29
+    19990204   Zoltan Boszormenyi <zbo...@mol.hu>
+	       Refined ARR support: enable MAPEN in set_mtrr_prepare()
+	       and disable MAPEN in set_mtrr_done().
+    19990205   Richard Gooch <rgo...@atnf.csiro.au>
+	       Minor cleanups.
+  v1.30
+    19990208   Zoltan Boszormenyi <zbo...@mol.hu>
+               Protect plain 6x86s (and other processors without the
+               Page Global Enable feature) against accessing CR4 in
+               set_mtrr_prepare() and set_mtrr_done().
+    19990210   Richard Gooch <rgo...@atnf.csiro.au>
+	       Turned <set_mtrr_up> and <get_mtrr> into function pointers.
+  v1.31
+    19990212   Zoltan Boszormenyi <zbo...@mol.hu>
+               Major rewrite of cyrix_arr_init(): do not touch ARRs,
+               leave them as the BIOS have set them up.
+               Enable usage of all 8 ARRs.
+               Avoid multiplications by 3 everywhere and other
+               code clean ups/speed ups.
+    19990213   Zoltan Boszormenyi <zbo...@mol.hu>
+               Set up other Cyrix processors identical to the boot cpu.
+               Since Cyrix don't support Intel APIC, this is l'art pour l'art.
+               Weigh ARRs by size:
+               If size <= 32M is given, set up ARR# we were given.
+               If size >  32M is given, set up ARR7 only if it is free,
+               fail otherwise.
+    19990214   Zoltan Boszormenyi <zbo...@mol.hu>
+               Also check for size >= 256K if we are to set up ARR7,
+               mtrr_add() returns the value it gets from set_mtrr()
+    19990218   Zoltan Boszormenyi <zbo...@mol.hu>
+               Remove Cyrix "coma bug" workaround from here.
+               Moved to linux/arch/i386/kernel/setup.c and
+               linux/include/asm-i386/bugs.h
+    19990228   Richard Gooch <rgo...@atnf.csiro.au>
+	       Added #ifdef CONFIG_DEVFS_FS
+	       Added MTRRIOC_KILL_ENTRY ioctl(2)
+	       Trap for counter underflow in <mtrr_file_del>.
+	       Trap for 4 MiB aligned regions for PPro, stepping <= 7.
+    19990301   Richard Gooch <rgo...@atnf.csiro.au>
+	       Created <get_free_region> hook.
+    19990305   Richard Gooch <rgo...@atnf.csiro.au>
+	       Temporarily disable AMD support now MTRR capability flag is set.
+  v1.32
+    19990308   Zoltan Boszormenyi <zbo...@mol.hu>
+	       Adjust my changes (19990212-19990218) to Richard Gooch's
+	       latest changes. (19990228-19990305)
+  v1.33
+    19990309   Richard Gooch <rgo...@atnf.csiro.au>
+	       Fixed typo in <printk> message.
+    19990310   Richard Gooch <rgo...@atnf.csiro.au>
+	       Support K6-II/III based on Alan Cox's <al...@redhat.com> patches.
+  v1.34
X */
X #include <linux/types.h>
X #include <linux/errno.h>
@@ -163,11 +227,12 @@
X #include <asm/segment.h>
X #include <asm/bitops.h>
X #include <asm/atomic.h>
+#include <asm/msr.h>
X 
X #include <asm/hardirq.h>
X #include "irq.h"
X 
-#define MTRR_VERSION            "1.26 (19981001)"
+#define MTRR_VERSION            "1.34 (19990310)"
X 
X #define TRUE  1
X #define FALSE 0
@@ -197,7 +262,7 @@
X #  define MTRR_CHANGE_MASK_DEFTYPE   0x04
X #endif
X 
-/* In the processor's MTRR interface, the MTRR type is always held in
+/* In the Intel processor's MTRR interface, the MTRR type is always held in
X    an 8 bit field: */
X typedef u8 mtrr_type;
X 
@@ -207,9 +272,12 @@
X #ifdef __SMP__
X #  define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
X #else
-#  define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE)
+#  define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
+						       TRUE)
X #endif
X 
+#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule ();
+
X #ifndef CONFIG_PROC_FS
X #  define compute_ascii() while (0)
X #endif
@@ -233,49 +301,30 @@
X     unsigned long deftype_lo;
X     unsigned long deftype_hi;
X     unsigned long cr4val;
+    unsigned long ccr3;
X };
X 
-/*
- * Access to machine-specific registers (available on 586 and better only)
- * Note: the rd* operations modify the parameters directly (without using
- * pointer indirection), this allows gcc to optimize better
- */
-#define rdmsr(msr,val1,val2) \
-       __asm__ __volatile__("rdmsr" \
-			    : "=a" (val1), "=d" (val2) \
-			    : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
-     __asm__ __volatile__("wrmsr" \
-			  : /* no outputs */ \
-			  : "c" (msr), "a" (val1), "d" (val2))
-
-#define rdtsc(low,high) \
-     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdpmc(counter,low,high) \
-     __asm__ __volatile__("rdpmc" \
-			  : "=a" (low), "=d" (high) \
-			  : "c" (counter))
-
X 
-/* Put the processor into a state where MTRRs can be safely set. */
-static void set_mtrr_prepare(struct set_mtrr_context *ctxt)
+/*  Put the processor into a state where MTRRs can be safely set  */
+static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
X {
X     unsigned long tmp;
X 
-    /* disable interrupts locally */
+    /*  Disable interrupts locally  */
X     __save_flags (ctxt->flags); __cli ();
X 
-    /* save value of CR4 and clear Page Global Enable (bit 7) */
-    asm volatile ("movl  %%cr4, %0\n\t"
-		  "movl  %0, %1\n\t"
-		  "andb  $0x7f, %b1\n\t"
-		  "movl  %1, %%cr4\n\t"
-                  : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return;
X 
-    /* disable and flush caches. Note that wbinvd flushes the TLBs as
-       a side-effect. */
+    /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+	asm volatile ("movl  %%cr4, %0\n\t"
+		      "movl  %0, %1\n\t"
+		      "andb  $0x7f, %b1\n\t"
+		      "movl  %1, %%cr4\n\t"
+		      : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+
+    /*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	a side-effect  */
X     asm volatile ("movl  %%cr0, %0\n\t"
X 		  "orl   $0x40000000, %0\n\t"
X 		  "wbinvd\n\t"
@@ -283,64 +332,108 @@
X 		  "wbinvd\n\t"
X 		  : "=r" (tmp) : : "memory");
X 
-    /* disable MTRRs, and set the default type to uncached. */
-    rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
-    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	/*  Disable MTRRs, and set the default type to uncached  */
+	rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+	break;
+      case X86_VENDOR_CYRIX:
+	tmp = getCx86 (CX86_CCR3);
+	setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
+	ctxt->ccr3 = tmp;
+	break;
+    }
X }   /*  End Function set_mtrr_prepare  */
X 
-
-/* Restore the processor after a set_mtrr_prepare */
-static void set_mtrr_done(struct set_mtrr_context *ctxt)
+/*  Restore the processor after a set_mtrr_prepare  */
+static void set_mtrr_done (struct set_mtrr_context *ctxt)
X {
X     unsigned long tmp;
X 
-    /* flush caches and TLBs */
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+    {
+	__restore_flags (ctxt->flags);
+	return;
+    }
+
+    /*  Flush caches and TLBs  */
X     asm volatile ("wbinvd" : : : "memory" );
X 
-    /* restore MTRRdefType */
-    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+    /*  Restore MTRRdefType  */
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+	break;
+      case X86_VENDOR_CYRIX:
+	setCx86 (CX86_CCR3, ctxt->ccr3);
+	break;
+    }
X 
-    /* enable caches */
+    /*  Enable caches  */
X     asm volatile ("movl  %%cr0, %0\n\t"
X 		  "andl  $0xbfffffff, %0\n\t"
X 		  "movl  %0, %%cr0\n\t"
X 		  : "=r" (tmp) : : "memory");
X 
-    /* restore value of CR4 */
-    asm volatile ("movl  %0, %%cr4"
-                  : : "r" (ctxt->cr4val) : "memory");
+    /*  Restore value of CR4  */
+    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+	asm volatile ("movl  %0, %%cr4"
+		      : : "r" (ctxt->cr4val) : "memory");
X 
-    /* re-enable interrupts locally (if enabled previously) */
+    /*  Re-enable interrupts locally (if enabled previously)  */
X     __restore_flags (ctxt->flags);
X }   /*  End Function set_mtrr_done  */
X 
-
-/* this function returns the number of variable MTRRs */
+/*  This function returns the number of variable MTRRs  */
X static unsigned int get_num_var_ranges (void)
X {
X     unsigned long config, dummy;
X 
-    rdmsr(MTRRcap_MSR, config, dummy);
-    return (config & 0xff);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	rdmsr (MTRRcap_MSR, config, dummy);
+	return (config & 0xff);
+	/*break;*/
+      case X86_VENDOR_CYRIX:
+	/*  Cyrix have 8 ARRs */
+	return 8;
+	/*break;*/
+      case X86_VENDOR_AMD:
+	return 2;
+	/*break;*/
+    }
+    return 0;
X }   /*  End Function get_num_var_ranges  */
X 
-
-/* non-zero if we have the write-combining memory type. */
+/*  Returns non-zero if we have the write-combining memory type  */
X static int have_wrcomb (void)
X {
X     unsigned long config, dummy;
X 
-    rdmsr(MTRRcap_MSR, config, dummy);
-    return (config & (1<<10));
-}
-
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	rdmsr (MTRRcap_MSR, config, dummy);
+	return (config & (1<<10));
+	/*break;*/
+      case X86_VENDOR_CYRIX:
+      case X86_VENDOR_AMD:
+	return 1;
+	/*break;*/
+    }
+    return 0;
+}   /*  End Function have_wrcomb  */
X 
-static void get_mtrr (unsigned int reg, unsigned long *base,
-		      unsigned long *size, mtrr_type *type)
+static void intel_get_mtrr (unsigned int reg, unsigned long *base,
+			    unsigned long *size, mtrr_type *type)
X {
X     unsigned long dummy, mask_lo, base_lo;
X 
-    rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy);
+    rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
X     if ((mask_lo & 0x800) == 0) {
X 	/* Invalid (i.e. free) range. */
X 	*base = 0;
@@ -364,11 +457,104 @@
X 
X     *base = (base_lo & 0xfffff000UL);
X     *type = (base_lo & 0xff);
-}   /*  End Function get_mtrr  */
+}   /*  End Function intel_get_mtrr  */
+
+static void cyrix_get_arr (unsigned int reg, unsigned long *base,
+			   unsigned long *size, mtrr_type *type)
+{
+    unsigned long flags;
+    unsigned char arr, ccr3, rcr, shift;
+
+    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
X 
+    /* Save flags and disable interrupts */
+    __save_flags (flags); __cli ();
X 
-static void set_mtrr_up (unsigned int reg, unsigned long base,
-			 unsigned long size, mtrr_type type, int do_safe)
+    ccr3 = getCx86 (CX86_CCR3);
+    setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);		/* enable MAPEN */
+    ((unsigned char *) base)[3]  = getCx86 (arr);
+    ((unsigned char *) base)[2]  = getCx86 (arr+1);
+    ((unsigned char *) base)[1]  = getCx86 (arr+2);
+    rcr = getCx86(CX86_RCR_BASE + reg);
+    setCx86 (CX86_CCR3, ccr3);				/* disable MAPEN */
+
+    /* Enable interrupts if it was enabled previously */
+    __restore_flags (flags);
+    
+    shift = ((unsigned char *) base)[1] & 0x0f;
+    *base &= 0xfffff000UL;
+
+    /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+     * Note: shift==0xf means 4G, this is unsupported.
+     */
+    if (shift)
+      *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+    else
+      *size = 0;
+
+    /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+    if (reg < 7) {
+      switch (rcr) {
+	case  1: *type = MTRR_TYPE_UNCACHABLE; break;
+	case  8: *type = MTRR_TYPE_WRBACK;     break;
+	case  9: *type = MTRR_TYPE_WRCOMB;     break;
+	case 24:
+	default: *type = MTRR_TYPE_WRTHROUGH;  break;
+      }
+    } else {
+      switch (rcr) {
+	case  0: *type = MTRR_TYPE_UNCACHABLE; break;
+	case  8: *type = MTRR_TYPE_WRCOMB;     break;
+	case  9: *type = MTRR_TYPE_WRBACK;     break;
+	case 25:
+	default: *type = MTRR_TYPE_WRTHROUGH;  break;
+      }
+    }
+}   /*  End Function cyrix_get_arr  */
+
+static void amd_get_mtrr (unsigned int reg, unsigned long *base,
+			  unsigned long *size, mtrr_type *type)
+{
+    unsigned long low, high;
+
+    rdmsr (0xC0000085, low, high);
+    /*  Upper dword is region 1, lower is region 0  */
+    if (reg == 1) low = high;
+    /*  The base masks off on the right alignment  */
+    *base = low & 0xFFFE0000;
+    *type = 0;
+    if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
+    if (low & 2) *type = MTRR_TYPE_WRCOMB;
+    if ( !(low & 3) )
+    {
+	*size = 0;
+	return;
+    }
+    /*
+     *	This needs a little explaining. The size is stored as an
+     *	inverted mask of bits of 128K granularity 15 bits long offset
+     *	2 bits
+     *
+     *	So to get a size we do invert the mask and add 1 to the lowest
+     *	mask bit (4 as its 2 bits in). This gives us a size we then shift
+     *	to turn into 128K blocks
+     *
+     *	eg		111 1111 1111 1100      is 512K
+     *
+     *	invert		000 0000 0000 0011
+     *	+1		000 0000 0000 0100
+     *	*128K	...
+     */
+    low = (~low) & 0x1FFFC;
+    *size = (low + 4) << 15;
+    return;
+}   /*  End Function amd_get_mtrr  */
+
+static void (*get_mtrr) (unsigned int reg, unsigned long *base,
+			 unsigned long *size, mtrr_type *type) = NULL;
+
+static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
+			       unsigned long size, mtrr_type type, int do_safe)
X /*  [SUMMARY] Set variable MTRR register on the local CPU.
X     <reg> The register to set.
X     <base> The base address of the region.
@@ -376,6 +562,7 @@
X     <type> The type of the region.
X     <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
X     be done externally.
+    [RETURNS] Nothing.
X */
X {
X     struct set_mtrr_context ctxt;
@@ -393,8 +580,92 @@
X 	wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
X     }
X     if (do_safe) set_mtrr_done (&ctxt);
-}   /*  End Function set_mtrr_up  */
+}   /*  End Function intel_set_mtrr_up  */
+
+static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
+			      unsigned long size, mtrr_type type, int do_safe)
+{
+    struct set_mtrr_context ctxt;
+    unsigned char arr, arr_type, arr_size;
+
+    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
+
+    /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+    size >>= (reg < 7 ? 12 : 18);
+    size &= 0x7fff; /* make sure arr_size <= 14 */
+    for(arr_size = 0; size; arr_size++, size >>= 1);
+
+    if (reg<7) {
+      switch (type) {
+	case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;
+	case MTRR_TYPE_WRCOMB:		arr_type =  9; break;
+	case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;
+	default:			arr_type =  8; break;
+      }
+    } else {
+      switch (type) {
+	case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;
+	case MTRR_TYPE_WRCOMB:		arr_type =  8; break;
+	case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;
+	default:			arr_type =  9; break;
+      }
+    }
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    setCx86(arr,    ((unsigned char *) &base)[3]);
+    setCx86(arr+1,  ((unsigned char *) &base)[2]);
+    setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
+    setCx86(CX86_RCR_BASE + reg, arr_type);
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function cyrix_set_arr_up  */
+
+static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
+			     unsigned long size, mtrr_type type, int do_safe)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+    [RETURNS] Nothing.
+*/
+{
+    u32 low, high;
+    struct set_mtrr_context ctxt;
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    /*
+     *	Low is MTRR0 , High MTRR 1
+     */
+    rdmsr (0xC0000085, low, high);
+    /*
+     *	Blank to disable
+     */
+    if (size == 0)
+	*(reg ? &high : &low) = 0;
+    else
+	/* Set the register to the base (already shifted for us), the
+	   type (off by one) and an inverted bitmask of the size
+        	   
+	   The size is the only odd bit. We are fed say 512K
+	   We invert this and we get 111 1111 1111 1011 but
+	   if you subtract one and invert you get the desired
+	   111 1111 1111 1100 mask 
+	   */
+	*(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+    /*
+     *	The writeback rule is quite specific. See the manual. Its
+     *	disable local interrupts, write back the cache, set the mtrr
+     */
+    __asm__ __volatile__ ("wbinvd" : : : "memory");
+    wrmsr (0xC0000085, low, high);
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function amd_set_mtrr_up  */
X 
+static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
+			    unsigned long size, mtrr_type type,
+			    int do_safe) = NULL;
X      
X #ifdef __SMP__
X 
@@ -407,7 +678,7 @@
X };
X 
X 
-/* Get the MSR pair relating to a var range. */
+/*  Get the MSR pair relating to a var range  */
X __initfunc(static void get_mtrr_var_range (unsigned int index,
X 					   struct mtrr_var_range *vr))
X {
@@ -416,8 +687,8 @@
X }   /*  End Function get_mtrr_var_range  */
X 
X 
-/* Set the MSR pair relating to a var range. Returns TRUE if
-   changes are made. */
+/*  Set the MSR pair relating to a var range. Returns TRUE if
+    changes are made  */
X __initfunc(static int set_mtrr_var_range_testing (unsigned int index,
X 						  struct mtrr_var_range *vr))
X {
@@ -441,8 +712,7 @@
X     }
X     
X     return changed;
-}
-
+}   /*  End Function set_mtrr_var_range_testing  */
X 
X __initfunc(static void get_fixed_ranges(mtrr_type *frs))
X {
@@ -456,8 +726,7 @@
X  
X     for (i = 0; i < 8; i++)
X 	rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
-}
-
+}   /*  End Function get_fixed_ranges  */
X 
X __initfunc(static int set_fixed_ranges_testing(mtrr_type *frs))
X {
@@ -487,10 +756,8 @@
X 	    changed = TRUE;
X 	}
X     }
-
X     return changed;
-}
-
+}   /*  End Function set_fixed_ranges_testing  */
X 
X struct mtrr_state
X {
@@ -502,7 +769,7 @@
X };
X 
X 
-/* Grab all of the MTRR state for this CPU into *state. */
+/*  Grab all of the MTRR state for this CPU into *state  */
X __initfunc(static void get_mtrr_state(struct mtrr_state *state))
X {
X     unsigned int nvrs, i;
@@ -511,22 +778,22 @@
X 
X     nvrs = state->num_var_ranges = get_num_var_ranges();
X     vrs = state->var_ranges 
-              = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL);
+              = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
X     if (vrs == NULL)
X 	nvrs = state->num_var_ranges = 0;
X 
X     for (i = 0; i < nvrs; i++)
-	get_mtrr_var_range(i, &vrs[i]);
+	get_mtrr_var_range (i, &vrs[i]);
X     
-    get_fixed_ranges(state->fixed_ranges);
+    get_fixed_ranges (state->fixed_ranges);
X 
-    rdmsr(MTRRdefType_MSR, lo, dummy);
+    rdmsr (MTRRdefType_MSR, lo, dummy);
X     state->def_type = (lo & 0xff);
X     state->enabled = (lo & 0xc00) >> 10;
X }   /*  End Function get_mtrr_state  */
X 
X 
-/* Free resources associated with a struct mtrr_state */
+/*  Free resources associated with a struct mtrr_state  */
X __initfunc(static void finalize_mtrr_state(struct mtrr_state *state))
X {
X     if (state->var_ranges) kfree (state->var_ranges);
@@ -546,14 +813,14 @@
X     unsigned long change_mask = 0;
X 
X     for (i = 0; i < state->num_var_ranges; i++)
-	if (set_mtrr_var_range_testing(i, &state->var_ranges[i]))
+	if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) )
X 	    change_mask |= MTRR_CHANGE_MASK_VARIABLE;
X 
-    if (set_fixed_ranges_testing(state->fixed_ranges))
+    if ( set_fixed_ranges_testing(state->fixed_ranges) )
X 	change_mask |= MTRR_CHANGE_MASK_FIXED;
X     
-    /* set_mtrr_restore restores the old value of MTRRdefType,
-       so to set it we fiddle with the saved value. */
+    /*  Set_mtrr_restore restores the old value of MTRRdefType,
+	so to set it we fiddle with the saved value  */
X     if ((ctxt->deftype_lo & 0xff) != state->def_type
X 	|| ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled)
X     {
@@ -566,76 +833,63 @@
X 
X  
X static atomic_t undone_count;
-static void (*handler_func) (struct set_mtrr_context *ctxt, void *info);
-static void *handler_info;
X static volatile int wait_barrier_execute = FALSE;
X static volatile int wait_barrier_cache_enable = FALSE;
X 
-static void sync_handler (void)
+struct set_mtrr_data
+{
+    unsigned long smp_base;
+    unsigned long smp_size;
+    unsigned int smp_reg;
+    mtrr_type smp_type;
+};
+
+static void ipi_handler (void *info)
X /*  [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
X     [RETURNS] Nothing.
X */
X {
+    struct set_mtrr_data *data = info;
X     struct set_mtrr_context ctxt;
X 
X     set_mtrr_prepare (&ctxt);
-    /*  Notify master CPU that I'm at the barrier and then wait  */
+    /*  Notify master that I've flushed and disabled my cache  */
X     atomic_dec (&undone_count);
X     while (wait_barrier_execute) barrier ();
X     /*  The master has cleared me to execute  */
-    (*handler_func) (&ctxt, handler_info);
+    (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
+		    data->smp_type, FALSE);
X     /*  Notify master CPU that I've executed the function  */
X     atomic_dec (&undone_count);
X     /*  Wait for master to clear me to enable cache and return  */
X     while (wait_barrier_cache_enable) barrier ();
X     set_mtrr_done (&ctxt);
-}   /*  End Function sync_handler  */
+}   /*  End Function ipi_handler  */
X 
-static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
-					  void *info),
-			 void *info, int local)
-/*  [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled.
-    [PURPOSE] This function will synchronise all CPUs, flush and disable caches
-    on all CPUs, then call a specified function. When the specified function
-    finishes on all CPUs, caches are enabled on all CPUs.
-    <handler> The function to execute.
-    <info> An arbitrary information pointer which is passed to <<handler>>.
-    <local> If TRUE <<handler>> is executed locally.
-    [RETURNS] Nothing.
-*/
+static void set_mtrr_smp (unsigned int reg, unsigned long base,
+			  unsigned long size, mtrr_type type)
X {
-    unsigned long timeout;
+    struct set_mtrr_data data;
X     struct set_mtrr_context ctxt;
X 
-    mtrr_hook = sync_handler;
-    handler_func = handler;
-    handler_info = info;
+    data.smp_reg = reg;
+    data.smp_base = base;
+    data.smp_size = size;
+    data.smp_type = type;
X     wait_barrier_execute = TRUE;
X     wait_barrier_cache_enable = TRUE;
-    /*  Send a message to all other CPUs and wait for them to enter the
-	barrier  */
X     atomic_set (&undone_count, smp_num_cpus - 1);
-    smp_send_mtrr();
-    /*  Wait for it to be done  */
-    timeout = jiffies + JIFFIE_TIMEOUT;
-    while ( (atomic_read (&undone_count) > 0) &&
-	    time_before(jiffies, timeout) )
-	barrier ();
-    if (atomic_read (&undone_count) > 0)
-    {
+    /*  Flush and disable the local CPU's cache	and start the ball rolling on
+	other CPUs  */
+    set_mtrr_prepare (&ctxt);
+    if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
X 	panic ("mtrr: timed out waiting for other CPUs\n");
-    }
-    mtrr_hook = NULL;
-    /*  All other CPUs should be waiting for the barrier, with their caches
-	already flushed and disabled. Prepare for function completion
-	notification  */
+    /*  Wait for all other CPUs to flush and disable their caches  */
+    while (atomic_read (&undone_count) > 0) barrier ();
+    /* Set up for completion wait and then release other CPUs to change MTRRs*/
X     atomic_set (&undone_count, smp_num_cpus - 1);
-    /*  Flush and disable the local CPU's cache	and release the barier, which
-	should cause the other CPUs to execute the function. Also execute it
-	locally if required  */
-    set_mtrr_prepare (&ctxt);
X     wait_barrier_execute = FALSE;
-    if (local) (*handler) (&ctxt, info);
+    (*set_mtrr_up) (reg, base, size, type, FALSE);
X     /*  Now wait for other CPUs to complete the function  */
X     while (atomic_read (&undone_count) > 0) barrier ();
X     /*  Now all CPUs should have finished the function. Release the barrier to
@@ -643,41 +897,10 @@
X 	then enable the local cache and return  */
X     wait_barrier_cache_enable = FALSE;
X     set_mtrr_done (&ctxt);
-    handler_func = NULL;
-    handler_info = NULL;
-}   /*  End Function do_all_cpus  */
-
-
-struct set_mtrr_data
-{
-    unsigned long smp_base;
-    unsigned long smp_size;
-    unsigned int smp_reg;
-    mtrr_type smp_type;
-};
-
-static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info)
-{
-    struct set_mtrr_data *data = info;
-
-    set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type,
-		 FALSE);
-}   /*  End Function set_mtrr_handler  */
-
-static void set_mtrr_smp (unsigned int reg, unsigned long base,
-			  unsigned long size, mtrr_type type)
-{
-    struct set_mtrr_data data;
-
-    data.smp_reg = reg;
-    data.smp_base = base;
-    data.smp_size = size;
-    data.smp_type = type;
-    do_all_cpus (set_mtrr_handler, &data, TRUE);
X }   /*  End Function set_mtrr_smp  */
X 
X 
-/* Some BIOS's are fucked and don't set all MTRRs the same! */
+/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
X __initfunc(static void mtrr_state_warn (unsigned long mask))
X {
X     if (!mask) return;
@@ -720,6 +943,58 @@
X #endif
X }   /*  End Function init_table  */
X 
+static int generic_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free MTRR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i, max;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    max = get_num_var_ranges ();
+    for (i = 0; i < max; ++i)
+    {
+	(*get_mtrr) (i, &lbase, &lsize, <ype);
+	if (lsize < 1) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function generic_get_free_region  */
+
+static int cyrix_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free ARR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    /* If we are to set up a region >32M then look at ARR7 immediately */
+    if (size > 0x2000000UL) {
+	cyrix_get_arr (7, &lbase, &lsize, <ype);
+	if (lsize < 1) return 7;
+    /* else try ARR0-ARR6 first */
+    } else {
+	for (i = 0; i < 7; i++)
+	{
+	    cyrix_get_arr (i, &lbase, &lsize, <ype);
+	    if (lsize < 1) return i;
+	}
+	/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
+	cyrix_get_arr (i, &lbase, &lsize, <ype);
+	if ((lsize < 1) && (size >= 0x40000)) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function cyrix_get_free_region  */
+
+static int (*get_free_region) (unsigned long base,
+			       unsigned long size) = generic_get_free_region;
+
X int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
X 	      char increment)
X /*  [SUMMARY] Add an MTRR entry.
@@ -738,28 +1013,57 @@
X     unsigned long lbase, lsize, last;
X 
X     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
-    if ( (base & 0xfff) || (size & 0xfff) )
-    {
-	printk ("mtrr: size and base must be multiples of 4kB\n");
-	printk ("mtrr: size: %lx  base: %lx\n", size, base);
-	return -EINVAL;
-    }
-    if (base + size < 0x100000)
-    {
-	printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
-		base, size);
-	return -EINVAL;
-    }
-    /*  Check upper bits of base and last are equal and lower bits are 0 for
-	base and 1 for last  */
-    last = base + size - 1;
-    for (lbase = base; !(lbase & 1) && (last & 1);
-	 lbase = lbase >> 1, last = last >> 1);
-    if (lbase != last)
+    switch (boot_cpu_data.x86_vendor)
X     {
-	printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
-		base, size);
+      case X86_VENDOR_INTEL:
+	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
+	if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
+	     (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) )
+	{
+	    printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+	    return -EINVAL;
+	}
+	/*  Fall through  */
+      case X86_VENDOR_CYRIX:
+	if ( (base & 0xfff) || (size & 0xfff) )
+	{
+	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
+	    printk ("mtrr: size: %lx  base: %lx\n", size, base);
+	    return -EINVAL;
+	}
+	if (base + size < 0x100000)
+	{
+	    printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
+		    base, size);
+	    return -EINVAL;
+	}
+	/*  Check upper bits of base and last are equal and lower bits are 0
+	    for base and 1 for last  */
+	last = base + size - 1;
+	for (lbase = base; !(lbase & 1) && (last & 1);
+	     lbase = lbase >> 1, last = last >> 1);
+	if (lbase != last)
+	{
+	    printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+		    base, size);
+	    return -EINVAL;
+	}
+	break;
+      case X86_VENDOR_AMD:
+    	/* Apply the K6 block alignment and size rules 
+    	   In order
+    	      o Uncached or gathering only
+    	      o 128K or bigger block
+    	      o Power of 2 block
+    	      o base suitably aligned to the power
+    	  */
+    	if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+	    (size & ~(size-1))-size || (base & (size-1)))
+	    return -EINVAL;
+	break;
+      default:
X 	return -EINVAL;
+	/*break;*/
X     }
X     if (type >= MTRR_NUM_TYPES)
X     {
@@ -775,10 +1079,10 @@
X     increment = increment ? 1 : 0;
X     max = get_num_var_ranges ();
X     /*  Search for existing MTRR  */
-    spin_lock (&main_lock);
+    spin_lock_reschedule (&main_lock);
X     for (i = 0; i < max; ++i)
X     {
-	get_mtrr (i, &lbase, &lsize, <ype);
+	(*get_mtrr) (i, &lbase, &lsize, <ype);
X 	if (base >= lbase + lsize) continue;
X 	if ( (base < lbase) && (base + size <= lbase) ) continue;
X 	/*  At this point we know there is some kind of overlap/enclosure  */
@@ -804,19 +1108,18 @@
X 	return i;
X     }
X     /*  Search for an empty MTRR  */
-    for (i = 0; i < max; ++i)
+    i = (*get_free_region) (base, size);
+    if (i < 0)
X     {
-	get_mtrr (i, &lbase, &lsize, <ype);
-	if (lsize > 0) continue;
-	set_mtrr (i, base, size, type);
-	usage_table[i] = 1;
-	compute_ascii ();
X 	spin_unlock (&main_lock);
+	printk ("mtrr: no more MTRRs available\n");
X 	return i;
X     }
+    set_mtrr (i, base, size, type);
+    usage_table[i] = 1;
+    compute_ascii ();
X     spin_unlock (&main_lock);
-    printk ("mtrr: no more MTRRs available\n");
-    return -ENOSPC;
+    return i;
X }   /*  End Function mtrr_add  */
X 
X int mtrr_del (int reg, unsigned long base, unsigned long size)
@@ -836,13 +1139,13 @@
X 
X     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
X     max = get_num_var_ranges ();
-    spin_lock (&main_lock);
+    spin_lock_reschedule (&main_lock);
X     if (reg < 0)
X     {
X 	/*  Search for existing MTRR  */
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 05'
echo 'File patch-2.2.8 is continued in part 06'
echo 06 > _shar_seq_.tmp
exit 0
-- 
Thomas Koenig, Thomas...@ciw.uni-karlsruhe.de, ig...@dkauni2.bitnet.
The joy of engineering is to find a straight line on a double
logarithmic diagram.
#!/bin/sh
# this is part 06 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 06; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 	for (i = 0; i < max; ++i)
X 	{
-	    get_mtrr (i, &lbase, &lsize, <ype);
+	    (*get_mtrr) (i, &lbase, &lsize, <ype);
X 	    if ( (lbase == base) && (lsize == size) )
X 	    {
X 		reg = i;
@@ -862,7 +1165,7 @@
X 	printk ("mtrr: register: %d too big\n", reg);
X 	return -EINVAL;
X     }
-    get_mtrr (reg, &lbase, &lsize, <ype);
+    (*get_mtrr) (reg, &lbase, &lsize, <ype);
X     if (lsize < 1)
X     {
X 	spin_unlock (&main_lock);
@@ -913,7 +1216,9 @@
X 
X     reg = mtrr_del (-1, base, size);
X     if (reg < 0) return reg;
-    if (fcount != NULL) --fcount[reg];
+    if (fcount == NULL) return reg;
+    if (fcount[reg] < 1) return -EINVAL;
+    --fcount[reg];
X     return reg;
X }   /*  End Function mtrr_file_del  */
X 
@@ -1019,11 +1324,18 @@
X 	err = mtrr_file_del (sentry.base, sentry.size, file);
X 	if (err < 0) return err;
X 	break;
+      case MTRRIOC_KILL_ENTRY:
+	if ( !suser () ) return -EPERM;
+	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+	    return -EFAULT;
+	err = mtrr_del (-1, sentry.base, sentry.size);
+	if (err < 0) return err;
+	break;
X       case MTRRIOC_GET_ENTRY:
X 	if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
X 	    return -EFAULT;
X 	if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
-	get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+	(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
X 	gentry.type = type;
X 	if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
X 	     return -EFAULT;
@@ -1115,7 +1427,7 @@
X     max = get_num_var_ranges ();
X     for (i = 0; i < max; i++)
X     {
-	get_mtrr (i, &base, &size, &type);
+	(*get_mtrr) (i, &base, &size, &type);
X 	if (size < 1) usage_table[i] = 0;
X 	else
X 	{
@@ -1148,23 +1460,165 @@
X 
X #ifdef __SMP__
X 
+typedef struct {
+  unsigned long base;
+  unsigned long size;
+  mtrr_type type;
+} arr_state_t;
+
+arr_state_t arr_state[8] __initdata = {
+  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
+  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
+};
+
+unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
+
+__initfunc(static void cyrix_arr_init_secondary(void))
+{
+    struct set_mtrr_context ctxt;
+    int i;
+
+    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+     /* the CCRs are not contiguous */
+    for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
+    for(   ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]);
+    for(i=0; i<8; i++)
+      cyrix_set_arr_up(i,
+        arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE);
+
+    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+}   /*  End Function cyrix_arr_init_secondary  */
+
+#endif
+
+/*
+ * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
+ * with the SMM (System Management Mode) mode. So we need the following:
+ * Check whether SMI_LOCK (CCR3 bit 0) is set
+ *   if it is set, write a warning message: ARR3 cannot be changed!
+ *     (it cannot be changed until the next processor reset)
+ *   if it is reset, then we can change it, set all the needed bits:
+ *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ *   - disable access to SMM memory (CCR1 bit 2 reset)
+ *   - disable SMM mode (CCR1 bit 1 reset)
+ *   - disable write protection of ARR3 (CCR6 bit 1 reset)
+ *   - (maybe) disable ARR3
+ * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+ */
+__initfunc(static void cyrix_arr_init(void))
+{
+    struct set_mtrr_context ctxt;
+    unsigned char ccr[7];
+    int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+#ifdef __SMP__
+    int i;
+#endif
+
+    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+    /* Save all CCRs locally */
+    ccr[0] = getCx86 (CX86_CCR0);
+    ccr[1] = getCx86 (CX86_CCR1);
+    ccr[2] = getCx86 (CX86_CCR2);
+    ccr[3] = ctxt.ccr3;
+    ccr[4] = getCx86 (CX86_CCR4);
+    ccr[5] = getCx86 (CX86_CCR5);
+    ccr[6] = getCx86 (CX86_CCR6);
+
+    if (ccr[3] & 1)
+      ccrc[3] = 1;
+    else {
+      /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+       * access to SMM memory through ARR3 (bit 7).
+       */
+/*
+      if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
+      if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
+      if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
+*/
+      if (ccr[6] & 0x02) {
+        ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */
+        setCx86 (CX86_CCR6, ccr[6]);
+      }
+      /* Disable ARR3. */
+      /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+    }
+    /* If we changed CCR1 in memory, change it in the processor, too. */
+    if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
+
+    /* Enable ARR usage by the processor */
+    if (!(ccr[5] & 0x20)) {
+      ccr[5] |= 0x20; ccrc[5] = 1;
+      setCx86 (CX86_CCR5, ccr[5]);
+    }
+
+#ifdef __SMP__
+    for(i=0; i<7; i++) ccr_state[i] = ccr[i];
+    for(i=0; i<8; i++)
+      cyrix_get_arr(i,
+        &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);
+#endif
+
+    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+
+    if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n");
+    if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");
+/*
+    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
+    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
+    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
+*/
+    if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
+}   /*  End Function cyrix_arr_init  */
+
+__initfunc(static void mtrr_setup (void))
+{
+    printk ("mtrr: v%s Richard Gooch (rgo...@atnf.csiro.au)\n", MTRR_VERSION);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	get_mtrr = intel_get_mtrr;
+	set_mtrr_up = intel_set_mtrr_up;
+	break;
+      case X86_VENDOR_CYRIX:
+	printk ("mtrr: Using Cyrix style ARRs\n");
+	get_mtrr = cyrix_get_arr;
+	set_mtrr_up = cyrix_set_arr_up;
+	get_free_region = cyrix_get_free_region;
+	break;
+      case X86_VENDOR_AMD:
+	get_mtrr = amd_get_mtrr;
+	set_mtrr_up = amd_set_mtrr_up;
+	break;
+    }
+}   /*  End Function mtrr_setup  */
+
+#ifdef __SMP__
+
X static volatile unsigned long smp_changes_mask __initdata = 0;
X static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
X 
X __initfunc(void mtrr_init_boot_cpu (void))
X {
X     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
-    printk("mtrr: v%s Richard Gooch (rgo...@atnf.csiro.au)\n", MTRR_VERSION);
-
-    get_mtrr_state (&smp_mtrr_state);
+    mtrr_setup ();
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+ get_mtrr_state (&smp_mtrr_state);
+	break;
+      case X86_VENDOR_CYRIX:
+	cyrix_arr_init ();
+	break;
+    }
X }   /*  End Function mtrr_init_boot_cpu  */
X 
-__initfunc(void mtrr_init_secondary_cpu (void))
+__initfunc(static void intel_mtrr_init_secondary_cpu (void))
X {
X     unsigned long mask, count;
X     struct set_mtrr_context ctxt;
X 
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
X     /*  Note that this is not ideal, since the cache is only flushed/disabled
X 	for this CPU while the MTRRs are changed, but changing this requires
X 	more invasive changes to the way the kernel boots  */
@@ -1177,21 +1631,52 @@
X 	if (mask & 0x01) set_bit (count, &smp_changes_mask);
X 	mask >>= 1;
X     }
-}   /*  End Function mtrr_init_secondary_cpu  */
+}   /*  End Function intel_mtrr_init_secondary_cpu  */
X 
+__initfunc(void mtrr_init_secondary_cpu (void))
+{
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+ intel_mtrr_init_secondary_cpu ();
+	break;
+      case X86_VENDOR_CYRIX:
+	/* This is _completely theoretical_!
+	 * I assume here that one day Cyrix will support Intel APIC.
+	 * In reality on non-Intel CPUs we won't even get to this routine.
+	 * Hopefully no one will plug two Cyrix processors in a dual P5 board.
+	 *  :-)
+	 */
+	cyrix_arr_init_secondary ();
+	break;
+      default:
+	printk ("mtrr: SMP support incomplete for this vendor\n");
+	break;
+    }
+}   /*  End Function mtrr_init_secondary_cpu  */
X #endif  /*  __SMP__  */
X 
X __initfunc(int mtrr_init(void))
X {
X     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
-#  ifndef __SMP__
-    printk("mtrr: v%s Richard Gooch (rgo...@atnf.csiro.au)\n", MTRR_VERSION);
-#  endif
-
X #  ifdef __SMP__
-    finalize_mtrr_state (&smp_mtrr_state);
-    mtrr_state_warn (smp_changes_mask);
-#  endif /* __SMP__ */
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	finalize_mtrr_state (&smp_mtrr_state);
+	mtrr_state_warn (smp_changes_mask);
+	break;
+    }
+#  else /* __SMP__ */
+    mtrr_setup ();
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_CYRIX:
+	cyrix_arr_init ();
+	break;
+    }
+#  endif  /*  !__SMP__  */
X 
X #  ifdef CONFIG_PROC_FS
X     proc_register (&proc_root, &proc_root_mtrr);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.2.7/linux/arch/i386/kernel/process.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/process.c	Fri Apr 30 08:13:37 1999
@@ -111,6 +111,8 @@
X 	/* endless idle loop with no priority at all */
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();
+
X 	for (;;) {
X 		if (work)
X 			start_idle = jiffies;
@@ -139,6 +141,8 @@
X 	/* endless idle loop with no priority at all */
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();
+
X 	while(1) {
X 		if (current_cpu_data.hlt_works_ok && !hlt_counter &&
X 				 !current->need_resched)
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.2.7/linux/arch/i386/kernel/setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/setup.c	Mon May 10 10:32:45 1999
@@ -5,6 +5,10 @@
X  *
X  *  Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
X  *  and Martin Mares, November 1997.
+ *
+ *  Force Cyrix 6x86(MX) and M II processors to report MTRR capability
+ *  and fix against Cyrix "coma bug" by
+ *      Zoltan Boszormenyi <zbo...@mol.hu> February 1999.
X  */
X 
X /*
@@ -39,6 +43,7 @@
X #include <asm/io.h>
X #include <asm/smp.h>
X #include <asm/cobalt.h>
+#include <asm/msr.h>
X 
X /*
X  * Machine setup..
@@ -57,6 +62,7 @@
X unsigned int machine_id = 0;
X unsigned int machine_submodel_id = 0;
X unsigned int BIOS_revision = 0;
+unsigned int mca_pentium_flag = 0;
X 
X /*
X  * Setup options
@@ -244,11 +250,6 @@
X 	unsigned long memory_start, memory_end;
X 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
X 	int len = 0;
-	static unsigned char smptrap=0;
-
-	if (smptrap)
-		return;
-	smptrap=1;
X 
X #ifdef CONFIG_VISWS
X 	visws_get_board_type_and_rev();
@@ -381,16 +382,6 @@
X 
X }
X 
-#define rdmsr(msr,val1,val2) \
-       __asm__ __volatile__("rdmsr" \
-			    : "=a" (val1), "=d" (val2) \
-			    : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
-     __asm__ __volatile__("wrmsr" \
-			  : /* no outputs */ \
-			  : "c" (msr), "a" (val1), "d" (val2))
-
X __initfunc(static int get_model_name(struct cpuinfo_x86 *c))
X {
X 	unsigned int n, dummy, *v;
@@ -408,6 +399,14 @@
X 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
X 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
X 	c->x86_model_id[48] = 0;
+	/*  Set MTRR capability flag if appropriate  */
+	if(boot_cpu_data.x86 !=5)
+		return 1;
+	if((boot_cpu_data.x86_model == 9) ||
+	   ((boot_cpu_data.x86_model == 8) && 
+	    (boot_cpu_data.x86_mask >= 8)))
+		c->x86_capability |= X86_FEATURE_MTRR;
+
X 	return 1;
X }
X 
@@ -587,6 +586,10 @@
X 			(c->x86_model)++;
X 		} else             /* 686 */
X 			p = Cx86_cb+1;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		c->x86_capability |= X86_FEATURE_MTRR;
+		/* 6x86's contain this bug */
+		c->coma_bug = 1;
X 		break;
X 
X 	case 4: /* MediaGX/GXm */
@@ -611,11 +614,14 @@
X 
X         case 5: /* 6x86MX/M II */
X 		if (dir1 > 7) dir0_msn++;  /* M II */
+		else c->coma_bug = 1;      /* 6x86MX, it has the bug. */
X 		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
X 		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
X 		p = Cx86_cb+tmp;
X         	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
X 			(c->x86_model)++;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		c->x86_capability |= X86_FEATURE_MTRR;
X 		break;
X 
X 	case 0xf:  /* Cyrix 486 without DEVID registers */
@@ -869,7 +875,7 @@
X 	int sep_bug;
X 	static char *x86_cap_flags[] = {
X 	        "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
-	        "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
+	        "cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov",
X 	        "16", "17", "psn", "19", "20", "21", "22", "mmx",
X 	        "24", "kni", "26", "27", "28", "29", "30", "31"
X 	};
@@ -917,7 +923,6 @@
X 		} else if (c->x86_vendor == X86_VENDOR_INTEL) {
X 			x86_cap_flags[6] = "pae";
X 			x86_cap_flags[9] = "apic";
-			x86_cap_flags[12] = "mtrr";
X 			x86_cap_flags[14] = "mca";
X 			x86_cap_flags[16] = "pat";
X 			x86_cap_flags[17] = "pse36";
@@ -936,6 +941,7 @@
X 			        "hlt_bug\t\t: %s\n"
X 			        "sep_bug\t\t: %s\n"
X 			        "f00f_bug\t: %s\n"
+			        "coma_bug\t: %s\n"
X 			        "fpu\t\t: %s\n"
X 			        "fpu_exception\t: %s\n"
X 			        "cpuid level\t: %d\n"
@@ -945,6 +951,7 @@
X 			     c->hlt_works_ok ? "no" : "yes",
X 			     sep_bug ? "yes" : "no",
X 			     c->f00f_bug ? "yes" : "no",
+			     c->coma_bug ? "yes" : "no",
X 			     c->hard_math ? "yes" : "no",
X 			     (c->hard_math && ignore_irq13) ? "yes" : "no",
X 			     c->cpuid_level,
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.2.7/linux/arch/i386/kernel/smp.c	Wed Apr 28 11:37:29 1999
+++ linux/arch/i386/kernel/smp.c	Mon May 10 10:32:45 1999
@@ -40,10 +40,12 @@
X #include <linux/smp_lock.h>
X #include <linux/init.h>
X #include <asm/mtrr.h>
+#include <asm/msr.h>
X 
X #include "irq.h"
X 
-extern unsigned long start_kernel;
+#define JIFFIE_TIMEOUT 100
+
X extern void update_one_process( struct task_struct *p,
X 				unsigned long ticks, unsigned long user,
X 				unsigned long system, int cpu);
@@ -147,16 +149,7 @@
X  */
X #define APIC_DEFAULT_PHYS_BASE 0xfee00000
X 
-/*
- * Reads and clears the Pentium Timestamp-Counter
- */
-#define READ_TSC(x)	__asm__ __volatile__ (  "rdtsc" \
-				:"=a" (((unsigned long*)&(x))[0]),  \
-				 "=d" (((unsigned long*)&(x))[1]))
-
-#define CLEAR_TSC \
-	__asm__ __volatile__ ("\t.byte 0x0f, 0x30;\n"::\
-		"a"(0x00001000), "d"(0x00001000), "c"(0x10):"memory")
+#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000)
X 
X /*
X  *	Setup routine for controlling SMP activation
@@ -899,6 +892,7 @@
X  * Everything has been set up for the secondary
X  * CPUs - they just need to reload everything
X  * from the task structure
+ * This function must not return.
X  */
X void __init initialize_secondary(void)
X {
@@ -940,7 +934,6 @@
X 	/*
X 	 *	We need an idle process for each processor.
X 	 */
-
X 	kernel_thread(start_secondary, NULL, CLONE_PID);
X 	cpucount++;
X 
@@ -951,6 +944,8 @@
X 	idle->processor = i;
X 	__cpu_logical_map[cpucount] = i;
X 	cpu_number_map[i] = cpucount;
+	idle->has_cpu = 1; /* we schedule the first task manually */
+	idle->tss.eip = (unsigned long) start_secondary;
X 
X 	/* start_eip had better be page-aligned! */
X 	start_eip = setup_trampoline();
@@ -1183,6 +1178,7 @@
X 	/*  Must be done before other processors booted  */
X 	mtrr_init_boot_cpu ();
X #endif
+	init_idle();
X 	/*
X 	 *	Initialize the logical to physical CPU number mapping
X 	 *	and the per-CPU profiling counter/multiplier
@@ -1657,15 +1653,84 @@
X 	send_IPI_allbutself(STOP_CPU_VECTOR);
X }
X 
-/*
- * this function sends an 'reload MTRR state' IPI to all other CPUs
- * in the system. it goes straight through, completion processing
- * is done on the mttr.c level.
+/* Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
X  */
-
-void smp_send_mtrr(void)
+struct smp_call_function_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+	int wait;
+};
+static volatile struct smp_call_function_struct *smp_call_function_data = NULL;
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int retry,
+		       int wait)
+/*  [SUMMARY] Run a function on all other CPUs.
+    <func> The function to run. This must be fast and non-blocking.
+    <info> An arbitrary pointer to pass to the function.
+    <retry> If true, keep retrying until ready.
+    <wait> If true, wait until function has completed on other CPUs.
+    [RETURNS] 0 on success, else a negative status code. Does not return until
+    remote CPUs are nearly ready to execute <<func>> or are or have executed.
+*/
X {
-	send_IPI_allbutself(MTRR_CHANGE_VECTOR);
+	unsigned long timeout;
+	struct smp_call_function_struct data;
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+	if (retry) {
+		while (1) {
+			if (smp_call_function_data) {
+				schedule ();  /*  Give a mate a go  */
+				continue;
+			}
+			spin_lock (&lock);
+			if (smp_call_function_data) {
+				spin_unlock (&lock);  /*  Bad luck  */
+				continue;
+			}
+			/*  Mine, all mine!  */
+			break;
+		}
+	}
+	else {
+		if (smp_call_function_data) return -EBUSY;
+		spin_lock (&lock);
+		if (smp_call_function_data) {
+			spin_unlock (&lock);
+			return -EBUSY;
+		}
+	}
+	smp_call_function_data = &data;
+	spin_unlock (&lock);
+	data.func = func;
+	data.info = info;
+	atomic_set (&data.unstarted_count, smp_num_cpus - 1);
+	data.wait = wait;
+	if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1);
+	/*  Send a message to all other CPUs and wait for them to respond  */
+	send_IPI_allbutself (CALL_FUNCTION_VECTOR);
+	/*  Wait for response  */
+	timeout = jiffies + JIFFIE_TIMEOUT;
+	while ( (atomic_read (&data.unstarted_count) > 0) &&
+		time_before (jiffies, timeout) )
+		barrier ();
+	if (atomic_read (&data.unstarted_count) > 0) {
+		smp_call_function_data = NULL;
+		return -ETIMEDOUT;
+	}
+	if (wait)
+		while (atomic_read (&data.unfinished_count) > 0)
+			barrier ();
+	smp_call_function_data = NULL;
+	return 0;
X }
X 
X /*
@@ -1781,6 +1846,7 @@
X 		local_flush_tlb();
X 
X 	ack_APIC_irq();
+
X }
X 
X static void stop_this_cpu (void)
@@ -1803,12 +1869,19 @@
X 	stop_this_cpu();
X }
X 
-void (*mtrr_hook) (void) = NULL;
-
-asmlinkage void smp_mtrr_interrupt(void)
+asmlinkage void smp_call_function_interrupt(void)
X {
-	ack_APIC_irq();
-	if (mtrr_hook) (*mtrr_hook)();
+	void (*func) (void *info) = smp_call_function_data->func;
+	void *info = smp_call_function_data->info;
+	int wait = smp_call_function_data->wait;
+
+	ack_APIC_irq ();
+	/*  Notify initiating CPU that I've grabbed the data and am about to
+	    execute the function  */
+	atomic_dec (&smp_call_function_data->unstarted_count);
+	/*  At this point the structure may be out of scope unless wait==1  */
+	(*func) (info);
+	if (wait) atomic_dec (&smp_call_function_data->unfinished_count);
X }
X 
X /*
@@ -1949,7 +2022,7 @@
X 	/*
X 	 * We wrapped around just now. Let's start:
X 	 */
-	READ_TSC(t1);
+	rdtscll(t1);
X 	tt1=apic_read(APIC_TMCCT);
X 
X #define LOOPS (HZ/10)
@@ -1960,7 +2033,7 @@
X 		wait_8254_wraparound ();
X 
X 	tt2=apic_read(APIC_TMCCT);
-	READ_TSC(t2);
+	rdtscll(t2);
X 
X 	/*
X 	 * The APIC bus clock counter is 32 bits only, it
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.2.7/linux/arch/i386/kernel/time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/time.c	Thu Apr 29 11:53:41 1999
@@ -47,6 +47,7 @@
X #include <asm/io.h>
X #include <asm/irq.h>
X #include <asm/delay.h>
+#include <asm/msr.h>
X 
X #include <linux/mc146818rtc.h>
X #include <linux/timex.h>
@@ -83,8 +84,8 @@
X 	register unsigned long edx asm("dx");
X 
X 	/* Read the Time Stamp Counter */
-	__asm__("rdtsc"
-		:"=a" (eax), "=d" (edx));
+
+	rdtsc(eax,edx);
X 
X 	/* .. relative to previous jiffy (32 bits is enough) */
X 	eax -= last_tsc_low;	/* tsc_low delta */
@@ -443,7 +444,8 @@
X 		 */
X 	
X 		/* read Pentium cycle counter */
-		__asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
+
+		rdtscl(last_tsc_low);
X 
X 		outb_p(0x00, 0x43);     /* latch the count ASAP */
X 
@@ -566,12 +568,12 @@
X 		unsigned long endlow, endhigh;
X 		unsigned long count;
X 
-		__asm__ __volatile__("rdtsc":"=a" (startlow),"=d" (starthigh));
+		rdtsc(startlow,starthigh);
X 		count = 0;
X 		do {
X 			count++;
X 		} while ((inb(0x61) & 0x20) == 0);
-		__asm__ __volatile__("rdtsc":"=a" (endlow),"=d" (endhigh));
+		rdtsc(endlow,endhigh);
X 
X 		last_tsc_low = endlow;
X 
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c
--- v2.2.7/linux/arch/i386/kernel/visws_apic.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/i386/kernel/visws_apic.c	Thu May  6 16:12:23 1999
@@ -201,11 +201,13 @@
X 	{
X 		unsigned int status;
X /* XXX APIC EOI? */
-		status = desc->status & ~IRQ_REPLAY;
+		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
X 		action = NULL;
-		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
X 			action = desc->action;
-		desc->status = status | IRQ_INPROGRESS;
+			status |= IRQ_INPROGRESS;
+		}
+		desc->status = status;
X 	}
X 	spin_unlock(&irq_controller_lock);
X 
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.2.7/linux/arch/m68k/Makefile	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/Makefile	Tue May 11 09:57:14 1999
@@ -56,6 +56,11 @@
X CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES)
X LIBS += arch/m68k/lib/lib.a
X 
+ifdef CONFIG_Q40
+CORE_FILES := $(CORE_FILES) arch/m68k/q40/q40.o
+SUBDIRS := $(SUBDIRS) arch/m68k/q40
+endif
+
X ifdef CONFIG_AMIGA
X CORE_FILES := $(CORE_FILES) arch/m68k/amiga/amiga.o
X SUBDIRS := $(SUBDIRS) arch/m68k/amiga
@@ -81,6 +86,11 @@
X SUBDIRS := $(SUBDIRS) arch/m68k/apollo
X endif
X 
+ifdef CONFIG_MVME147
+CORE_FILES := $(CORE_FILES) arch/m68k/mvme147/mvme147.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mvme147
+endif
+
X ifdef CONFIG_MVME16x
X CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
X SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
@@ -89,6 +99,11 @@
X ifdef CONFIG_BVME6000
X CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
X SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
+endif
+
+ifdef CONFIG_SUN3X
+CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o
+SUBDIRS := $(SUBDIRS) arch/m68k/sun3x
X endif
X 
X ifdef CONFIG_M68040
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c
--- v2.2.7/linux/arch/m68k/bvme6000/config.c	Tue Dec 22 14:16:54 1998
+++ linux/arch/m68k/bvme6000/config.c	Tue May 11 09:57:14 1999
@@ -417,10 +417,10 @@
X static void scc_delay (void)
X {
X         int n;
-        char i;
+	volatile int trash;
X 
X         for (n = 0; n < 20; n++)
-                i = *(volatile char *)0;
+		trash = n;
X }
X 
X static void scc_write (char ch)
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.2.7/linux/arch/m68k/config.in	Tue Feb 23 15:21:32 1999
+++ linux/arch/m68k/config.in	Tue May 11 09:57:14 1999
@@ -37,6 +37,7 @@
X bool 'Apollo support' CONFIG_APOLLO
X bool 'VME (Motorola and BVM) support' CONFIG_VME
X if [ "$CONFIG_VME" = "y" ]; then
+  bool 'MVME147 support' CONFIG_MVME147
X   bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
X   bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
X fi
@@ -44,10 +45,13 @@
X if [ "$CONFIG_HP300" = "y" ]; then
X   bool 'DIO bus support' CONFIG_DIO
X fi
+bool 'Sun3x support' CONFIG_SUN3X
+  
X define_bool CONFIG_SUN3 n
X if [ "$CONFIG_PCI" = "y" ]; then
X   bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
X fi
+bool 'Q40/Q60 support' CONFIG_Q40
X 
X comment 'Processor type'
X bool '68020 support' CONFIG_M68020
@@ -94,6 +98,29 @@
X   fi
X fi
X bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT" != "n" ]; then
+    if [ "$CONFIG_AMIGA" != "n" ]; then
+      dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+      if [ "$CONFIG_ZORRO" != "n" ]; then
+        dep_tristate '    Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+      fi
+    fi
+    if [ "$CONFIG_Q40" != "n" ]; then
+       tristate '    Q40 Parallel port' CONFIG_PARPORT
+       if [ "$CONFIG_PARPORT" != "n" ]; then
+         define_bool CONFIG_PARPORT_PC y
+       fi
+    fi
+  fi
+  if [ "$CONFIG_ATARI" == "y" ]; then
+    dep_tristate '    Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+  fi
+fi
+
+
X endmenu
X 
X source drivers/block/Config.in
@@ -147,6 +174,7 @@
X     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
X     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
X     bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI
+    dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
X     bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
X #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
X   fi
@@ -167,6 +195,10 @@
X fi
X #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
X 
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+  bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI
+fi
+
X if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
X   bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
X fi
@@ -175,6 +207,10 @@
X   bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
X fi
X 
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
+fi
+
X endmenu
X 
X fi
@@ -219,6 +255,9 @@
X #  bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
X   bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
X fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+  tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
+fi
X if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
X   tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
X fi
@@ -232,9 +271,17 @@
X     tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET
X   fi
X fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'Sun3x Lance support' CONFIG_SUNLANCE
+fi
X if [ "$CONFIG_HP300" = "y" ]; then
X   bool 'HP on-board LANCE support' CONFIG_HPLANCE
X fi
+if [ "$CONFIG_Q40" = "y" ]; then
+  if [ ! "$CONFIG_PARPORT" = "n" ]; then
+    dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+  fi
+fi
X fi
X endmenu
X 
@@ -243,6 +290,23 @@
X mainmenu_option next_comment
X comment 'Character devices'
X  
+if [ "$CONFIG_Q40" = "y" ]; then
+   tristate 'Q40 Standard/generic serial support' CONFIG_SERIAL
+fi
+
+if [ "$CONFIG_SERIAL" = "y" ]; then
+   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+   bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
+fi
+
+if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
+   bool '   Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
+   bool '   Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+#   bool '   Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
+   bool '   Support special multiport boards' CONFIG_SERIAL_MULTIPORT
+   bool '   Support the Bell Technologies HUB6 card' CONFIG_HUB6
+fi
+
X if [ "$CONFIG_VME" = "n" ]; then
X   define_bool CONFIG_VT y
X   if [ "$CONFIG_VT" = "y" ]; then
@@ -254,10 +318,17 @@
X   define_bool CONFIG_NVRAM y
X fi
X 
-tristate 'Parallel printer support' CONFIG_M68K_PRINTER
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
-fi
+if [ "$CONFIG_PARPORT" = "n" ]; then
+  tristate 'Parallel printer support' CONFIG_M68K_PRINTER
+  if [ "$CONFIG_ZORRO" = "y" ]; then
+    dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
+  fi
+else
+  dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+  if [ "$CONFIG_PRINTER" != "n" ]; then
+    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+  fi
+fi   
X if [ "$CONFIG_AMIGA" = "y" ]; then
X   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
X fi
@@ -280,13 +351,17 @@
X fi
X if [ "$CONFIG_AMIGA" = "y" ]; then
X   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
-  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
+  if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+    tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+  fi
X fi
-if [ "$CONFIG_ZORRO" = "y" ]; then
-  tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
-  dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
-  dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
-  tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+if [ "$CONFIG_PARPORT" = "n" ]; then
+  if [ "$CONFIG_ZORRO" = "y" ]; then
+    tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
+    dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
+    dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
+    tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+  fi
X fi
X if [ "$CONFIG_MAC" = "y" ]; then
X   bool 'Mac SCC serial support' CONFIG_MAC_SCC
@@ -294,18 +369,32 @@
X if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
X   tristate 'HP DCA serial support' CONFIG_HPDCA
X fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+  bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS
+  if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+    bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
+    bool 'Sun mouse support' CONFIG_SUN_MOUSE
+    define_bool CONFIG_SBUS y
+    define_bool CONFIG_SBUSCHAR y
+    define_bool CONFIG_SUN_SERIAL y
+  fi  
+fi
X if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
-     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
+     "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
+     "$CONFIG_SUN3X" = "y" ]; then
X   if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
X        "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
X        "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
X        "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
-       "$CONFIG_HPDCA" = "y" ]; then
+       "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
X     bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
X   fi
X fi
X if [ "$CONFIG_VME" = "y" ]; then
X   define_bool CONFIG_SERIAL_CONSOLE y
+  if [ "$CONFIG_MVME147" = "y" ]; then
+    bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
+  fi
X   if [ "$CONFIG_MVME16x" = "y" ]; then
X     bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
X     bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.2.7/linux/arch/m68k/kernel/entry.S	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/kernel/entry.S	Tue May 11 09:57:14 1999
@@ -164,8 +164,17 @@
X 
X 	movel	%sp,%sp@-
X 	movel	%d0,%sp@- 		|  put vector # on stack
+#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
+	btstb	#4,0xff000000	| Q40 floppy needs very special treatment ...
+	jbeq	1f
+	btstb	#3,0xff000004		
+	jbeq	1f
+	jbsr	SYMBOL_NAME(floppy_hardint)
+	jbra	3f
+1:		
+#endif		
X 	jbsr	SYMBOL_NAME(process_int)|  process the IRQ
-	addql	#8,%sp			|  pop parameters off stack
+3:     	addql	#8,%sp			|  pop parameters off stack
X 
X SYMBOL_NAME_LABEL(ret_from_interrupt)
X 	subql	#1,SYMBOL_NAME(local_irq_count)
@@ -295,6 +304,8 @@
X 2:	fmovemx	%fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
X 	fmoveml	%fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
X 3:
+	/* Return previous task in %d1 */
+	movel	%curptr,%d1
X 
X 	/* switch to new task (a1 contains new task) */
X 	movel	%a1,%curptr
@@ -320,7 +331,14 @@
X 	movec	%d0,%cacr
X 
X 	/* switch the root pointer */
+#ifdef CPU_M68030_ONLY
+	.chip	68030
+	pmovefd	%a1@(TASK_TSS+TSS_CRP),%crp
+	.chip	68k
+	pflush	#0,#4
+#else
X 	pmove	%a1@(TASK_TSS+TSS_CRP),%crp
+#endif
X #endif
X 
X #if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.2.7/linux/arch/m68k/kernel/head.S	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/kernel/head.S	Tue May 11 09:57:14 1999
@@ -23,6 +23,7 @@
X ** 98/04/25 Phil Blundell: added HP300 support
X ** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
X **            for linux-2.1.115
+** 9/02/11  Richard Zidlicky: added Q40 support (initial vesion 99/01/01) 
X **
X ** This file is subject to the terms and conditions of the GNU General Public
X ** License. See the file README.legal in the main directory of this archive
@@ -303,6 +304,12 @@
X .globl SYMBOL_NAME(availmem)
X .globl SYMBOL_NAME(m68k_pgtable_cachemode)
X .globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#ifdef CONFIG_MVME16x
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+#ifdef CONFIG_Q40
+.globl SYMBOL_NAME(q40_mem_cptr)	
+#endif		
X 
X CPUTYPE_040	= 1	/* indicates an 040 */
X CPUTYPE_060	= 2	/* indicates an 060 */
@@ -512,13 +519,15 @@
X #endif
X .endm
X 
-
X #define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
X #define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
X #define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
+#define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab
X #define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
X #define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
X #define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
+#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
+#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
X 
X #define is_040_or_060(lab)	btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab
X #define is_not_040_or_060(lab)	btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab
@@ -552,9 +561,11 @@
X 	.long	BOOTINFOV_MAGIC
X 	.long	MACH_AMIGA, AMIGA_BOOTI_VERSION
X 	.long	MACH_ATARI, ATARI_BOOTI_VERSION
+	.long	MACH_MVME147, MVME147_BOOTI_VERSION
X 	.long	MACH_MVME16x, MVME16x_BOOTI_VERSION
X 	.long	MACH_BVME6000, BVME6000_BOOTI_VERSION
X 	.long	MACH_MAC, MAC_BOOTI_VERSION
+	.long	MACH_Q40, Q40_BOOTI_VERSION	
X 	.long	0
X 1:	jra	SYMBOL_NAME(__start)
X 
@@ -859,7 +870,12 @@
X 	/*
X 	 * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
X 	 */
-	mmu_map	#0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+	mmu_map		#0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+	/*
+	 * Map the Zorro III I/O space with transparent translation
+	 * for frame buffer memory etc.
+	 */
+	mmu_map_tt	#1,#0x40000000,#0x20000000,#_PAGE_NOCACHE_S
X 
X 	jbra	L(mmu_init_done)
X 
@@ -867,7 +883,8 @@
X 	/*
X 	 * 030:	Map the 32Meg range physical 0x0 upto logical 0x8000.0000
X 	 */
-	mmu_map	#0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+	mmu_map		#0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+	mmu_map_tt	#1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030
X 
X 	jbra	L(mmu_init_done)
X 
@@ -926,6 +943,25 @@
X L(mmu_init_not_atari):
X #endif
X 
+#ifdef CONFIG_Q40
+	is_not_q40(L(notq40))
+	/*
+	 * add transparent mapping for 0xff00 0000 - 0xffff ffff
+	 * non-cached serialized etc..
+	 * this includes master chip, DAC, RTC and ISA ports
+	 * 0xfe000000-0xfeffffff is for screen and ROM
+	 */
+
+	putc    'Q'
+
+	mmu_map_tt	#0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W
+	mmu_map_tt	#1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S
+	
+	jbra	L(mmu_init_done)
+	
+L(notq40):		
+#endif	
+	
X #ifdef CONFIG_HP300
X 	is_not_hp300(L(nothp300))
X 
@@ -940,6 +976,24 @@
X 
X #endif
X 
+#ifdef CONFIG_MVME147
+
+       is_not_mvme147(L(not147))
+
+       /*
+	* On MVME147 we have already created kernel page tables for
+	* 4MB of RAM at address 0, so now need to do a transparent
+	* mapping of the top of memory space.  Make it 0.5GByte for now,
+	* so we can access on-board i/o areas.
+	*/
+
+       mmu_map_tt      #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030
+
+       jbra    L(mmu_init_done)
+
+L(not147):
+#endif /* CONFIG_MVME147 */
+
X #ifdef CONFIG_MVME16x
X 
X 	is_not_mvme16x(L(not16x))
@@ -965,7 +1019,7 @@
X 	 * 0xffe00000->0xffe1ffff.
X 	 */
X 
-	mmu_map_tt	1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+	mmu_map_tt	#1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
X 
X 	jbra	L(mmu_init_done)
X 
@@ -985,7 +1039,7 @@
X 	 * clash with User code virtual address space.
X 	 */
X 
-	mmu_map_tt	1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+	mmu_map_tt	#1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
X 
X 	jbra	L(mmu_init_done)
X 
@@ -1052,13 +1106,23 @@
X 	mmu_map_eq	#0x50000000,#0x02000000,%d3
X 	mmu_map_eq	#0x60000000,#0x00400000,%d3
X 	mmu_map_eq	#0x9c000000,#0x00400000,%d3
-	mmu_map_tt	1,#0xf8000000,#0x08000000,%d3
+	mmu_map_tt	#1,#0xf8000000,#0x08000000,%d3
X 
X 	jbra	L(mmu_init_done)
X 
X L(mmu_init_not_mac):
X #endif
X 
+#ifdef CONFIG_SUN3X
+	is_not_sun3x(L(notsun3x))
+
+	/* setup tt1 for I/O */
+	mmu_map_tt	#1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S
+
+L(notsun3x):
+	jbra	L(mmu_init_done)
+#endif
+
X L(mmu_init_done):
X 
X 	putc	'G'
@@ -1214,6 +1278,14 @@
X 1:
X #endif
X 
+#ifdef CONFIG_SUN3X
+	is_not_sun3x(1f)
+
+	/* enable copro */
+	oriw	#0x4000,0x61000000
+1:
+#endif
+
X /*
X  * Fixup the addresses for the kernel pointer table and availmem.
X  * Convert them from physical addresses to virtual addresses.
@@ -1780,7 +1852,7 @@
X 	/* Extract the highest bit set
X 	 */
X 	bfffo	ARG3{#0,#32},%d1
-	cmpw	#8,%d0
+	cmpw	#8,%d1
X 	jcc	L(do_map)
X 
X 	/* And get the mask
@@ -2155,7 +2227,9 @@
X 	/* Temporary allocate a page table and insert it into the ptr table
X 	 */
X 	movel	%a1@,%d0
-	addl	#PTR_TABLE_SIZE*4,%a1@
+	/* The 512 should be PAGE_TABLE_SIZE*4, but that violates the
+	   alignment restriction for pointer tables on the '0[46]0.  */
+	addl	#512,%a1@
X 	orw	#_PAGE_TABLE+_PAGE_ACCESSED,%d0
X 	movel	%d0,%a0@
X 	dputs	" (new)"
@@ -2703,6 +2777,31 @@
X L(serial_init_not_mac):
X #endif	/* CONFIG_MAC */
X 
+#ifdef CONFIG_Q40
+	is_not_q40(2f)
+/* debug output goes into SRAM, so we don't do it unless requested
+   - check for '%LX$' signature in SRAM   */
+	lea	%pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+	move.l	#0xff020010,%a1@  /* must be inited - also used by debug=mem */
+	move.l	#0xff020000,%a1   
+	cmp.b	#'%',%a1@
+	bne	2f	/*nodbg*/
+	addq.w	#4,%a1
+	cmp.b	#'L',%a1@
+	bne	2f	/*nodbg*/
+	addq.w	#4,%a1
+	cmp.b	#'X',%a1@
+	bne	2f	/*nodbg*/
+	addq.w	#4,%a1
+	cmp.b	#'$',%a1@
+	bne	2f	/*nodbg*/
+	/* signature OK */
+	lea	%pc@(L(q40_do_debug)),%a1
+	tas	%a1@
+/*nodbg: q40_do_debug is 0 by default*/	
+2:		
+#endif	
+	
X L(serial_init_done):
X func_return	serial_init
X 
@@ -2792,6 +2891,15 @@
X 4:
X #endif	/* CONFIG_ATARI */
X 
+#ifdef CONFIG_MVME147
+	is_not_mvme147(2f)
+1:	btst	#2,M147_SCC_CTRL_A
+	jeq	1b
+	moveb	%d0,M147_SCC_DATA_A
+	jbra	L(serial_putc_done)
+2:
+#endif
+
X #ifdef CONFIG_MVME16x
X 	is_not_mvme16x(2f)
X 	/*
@@ -2805,7 +2913,7 @@
X 	moveml	%sp@+,%d0-%d7/%a2-%a6
X 	jbra	L(serial_putc_done)
X 2:
-#endif CONFIG_MVME162 | CONFIG_MVME167
+#endif CONFIG_MVME16x
X 
X #ifdef CONFIG_BVME6000
X 	is_not_bvme6000(2f)
@@ -2819,6 +2927,18 @@
X 2:
X #endif
X 
+#ifdef CONFIG_Q40
+	is_not_q40(2f)
+	tst.l	%pc@(L(q40_do_debug))	/* only debug if requested */
+	beq	2f
+	lea	%pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+	move.l	%a1@,%a0
+	move.b	%d0,%a0@
+	addq.l	#4,%a0
+	move.l	%a0,%a1@
+2:		
+#endif	
+
X L(serial_putc_done):
X func_return	serial_putc
X 
@@ -3472,6 +3592,10 @@
X L(temp_mmap_mem):
X 	.long	0
X 
+#if defined (CONFIG_MVME147)
+M147_SCC_CTRL_A = 0xfffe3002
+M147_SCC_DATA_A = 0xfffe3003
+#endif
X 
X #if defined (CONFIG_BVME6000)
X BVME_SCC_CTRL_A	= 0xffb0000b
@@ -3508,4 +3632,10 @@
X #if defined(CONFIG_MVME16x)
X SYMBOL_NAME_LABEL(mvme_bdid_ptr)
X 	.long	0
+#endif
+#if defined(CONFIG_Q40)
+SYMBOL_NAME_LABEL(q40_mem_cptr)
+	.long 0
+L(q40_do_debug):	
+	.long 0	
X #endif
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v2.2.7/linux/arch/m68k/kernel/ints.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/kernel/ints.c	Tue May 11 09:57:14 1999
@@ -38,6 +38,10 @@
X #include <asm/page.h>
X #include <asm/machdep.h>
X 
+#ifdef CONFIG_Q40
+#include <asm/q40ints.h>
+#endif
+
X /* table for system interrupt handlers */
X static irq_handler_t irq_list[SYS_IRQS];
X 
@@ -177,14 +181,24 @@
X 
X /*
X  * Do we need these probe functions on the m68k?
+ *
+ *  ... may be usefull with ISA devices
X  */
X unsigned long probe_irq_on (void)
X {
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+		return q40_probe_irq_on();
+#endif
X 	return 0;
X }
X 
X int probe_irq_off (unsigned long irqs)
X {
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+		return q40_probe_irq_off(irqs);
+#endif
X 	return 0;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/m68k_defs.h linux/arch/m68k/kernel/m68k_defs.h
--- v2.2.7/linux/arch/m68k/kernel/m68k_defs.h	Thu Jan  7 15:11:36 1999
+++ linux/arch/m68k/kernel/m68k_defs.h	Tue May 11 09:57:14 1999
@@ -3,6 +3,47 @@
X  */
X 
X #define TS_MAGICKEY	0x5a5a5a5a
-#define TS_TSS 482
-#define TS_ESP0 502
-#define TS_FPU 506
+#define TASK_STATE 0
+#define TASK_FLAGS 4
+#define TASK_SIGPENDING 8
+#define TASK_NEEDRESCHED 20
+#define TASK_TSS 470
+#define TASK_MM 622
+#define TSS_KSP 0
+#define TSS_USP 4
+#define TSS_SR 8
+#define TSS_FS 10
+#define TSS_CRP 12
+#define TSS_ESP0 20
+#define TSS_FPREG 24
+#define TSS_FPCNTL 120
+#define TSS_FPSTATE 132
+#define PT_D0 32
+#define PT_ORIG_D0 36
+#define PT_SR 44
+#define PT_VECTOR 50
+#define IRQ_HANDLER 0
+#define IRQ_DEVID 8
+#define IRQ_NEXT 16
+#define STAT_IRQ 120
+#define BIR_TAG 0
+#define BIR_SIZE 2
+#define BIR_DATA 4
+#define FBCON_FONT_DESC_IDX 0
+#define FBCON_FONT_DESC_NAME 4
+#define FBCON_FONT_DESC_WIDTH 8
+#define FBCON_FONT_DESC_HEIGHT 12
+#define FBCON_FONT_DESC_DATA 16
+#define FBCON_FONT_DESC_PREF 20
+#define CUSTOMBASE -2132807680
+#define C_INTENAR 28
+#define C_INTREQR 30
+#define C_INTENA 154
+#define C_INTREQ 156
+#define C_SERDATR 24
+#define C_SERDAT 48
+#define C_SERPER 50
+#define CIAABASE -2134908927
+#define CIABBASE -2134913024
+#define C_PRA 0
+#define ZTWOBASE -2147483648
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.2.7/linux/arch/m68k/kernel/m68k_ksyms.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Tue May 11 09:57:14 1999
@@ -18,6 +18,7 @@
X #include <asm/checksum.h>
X #include <asm/hardirq.h>
X #include <asm/softirq.h>
+#include <asm/m68kserial.h>
X 
X asmlinkage long long __ashrdi3 (long long, int);
X extern char m68k_debug_device[];
@@ -54,6 +55,8 @@
X EXPORT_SYMBOL(disable_irq);
X EXPORT_SYMBOL(kernel_set_cachemode);
X EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
X 
X /* Networking helper routines. */
X EXPORT_SYMBOL(csum_partial_copy);
@@ -69,4 +72,5 @@
X 
X EXPORT_SYMBOL_NOVERS(__down_failed);
X EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
X EXPORT_SYMBOL_NOVERS(__up_wakeup);
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.2.7/linux/arch/m68k/kernel/process.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/kernel/process.c	Tue May 11 09:57:14 1999
@@ -169,15 +169,7 @@
X 
X asmlinkage int m68k_vfork(struct pt_regs *regs)
X {
-	int     child;
-	struct semaphore sem = MUTEX_LOCKED;
-
-	child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
-
-	if (child > 0)
-		down(&sem);
-
-	return child;
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
X }
X 
X asmlinkage int m68k_clone(struct pt_regs *regs)
@@ -190,7 +182,7 @@
X 	newsp = regs->d2;
X 	if (!newsp)
X 		newsp = rdusp();
-	return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs);
+	return do_fork(clone_flags, newsp, regs);
X }
X 
X int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.2.7/linux/arch/m68k/kernel/ptrace.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/kernel/ptrace.c	Tue May 11 09:57:14 1999
@@ -312,6 +312,7 @@
X asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
X {
X 	struct task_struct *child;
+	unsigned long flags;
X 	int ret;
X 
X 	lock_kernel();
@@ -343,21 +344,22 @@
X 		    (current->uid != child->uid) ||
X 	 	    (current->gid != child->egid) ||
X 		    (current->gid != child->sgid) ||
+	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
X 	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
X 			goto out;
X 		/* the same process cannot be attached many times */
X 		if (child->flags & PF_PTRACED)
X 			goto out;
X 		child->flags |= PF_PTRACED;
-		if (child->p_pptr != current) {
-			unsigned long flags;
X 
-			write_lock_irqsave(&tasklist_lock, flags);
+		write_lock_irqsave(&tasklist_lock, flags);
+		if (child->p_pptr != current) {
X 			REMOVE_LINKS(child);
X 			child->p_pptr = current;
X 			SET_LINKS(child);
-			write_unlock_irqrestore(&tasklist_lock, flags);
X 		}
+		write_unlock_irqrestore(&tasklist_lock, flags);
+
X 		send_sig(SIGSTOP, child, 1);
X 		ret = 0;
X 		goto out;
@@ -502,7 +504,6 @@
X 		}
X 
X 		case PTRACE_DETACH: { /* detach a process that was attached. */
-			unsigned long flags;
X 			long tmp;
X 
X 			ret = -EIO;
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.2.7/linux/arch/m68k/kernel/setup.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/kernel/setup.c	Tue May 11 09:57:14 1999
@@ -77,10 +77,26 @@
X int (*mach_set_clock_mmss) (unsigned long) = NULL;
X void (*mach_reset)( void );
X long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
X void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
X void (*mach_floppy_eject) (void) = NULL;
X #endif
+struct serial_struct;
+#ifdef CONFIG_SERIAL
+long serial_rs_init(void);
+int serial_register_serial(struct serial_struct *);
+void serial_unregister_serial(int);
+long ser_console_init(long, long );
+#endif
+#if defined(CONFIG_USERIAL)||defined(CONFIG_BVME6000_SCC)||defined(CONFIG_MVME162_SCC)||defined(CONFIG_HPDCA)||defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)||defined(CONFIG_MAC_SCC)||defined(CONFIG_ATARI_MIDI)||defined(CONFIG_ATARI_SCC)||defined(CONFIG_ATARI_MFPSER)
+#define M68K_SERIAL
+#endif
+#ifdef M68K_SERIAL
+long m68k_rs_init(void);
+int m68k_register_serial(struct serial_struct *);
+void m68k_unregister_serial(int);
+long m68k_serial_console_init(long, long );
+#endif
X #ifdef CONFIG_HEARTBEAT
X void (*mach_heartbeat) (int) = NULL;
X #endif
@@ -97,15 +113,19 @@
X extern int amiga_parse_bootinfo(const struct bi_record *);
X extern int atari_parse_bootinfo(const struct bi_record *);
X extern int mac_parse_bootinfo(const struct bi_record *);
+extern int q40_parse_bootinfo(const struct bi_record *);
X 
X extern void config_amiga(void);
X extern void config_atari(void);
X extern void config_mac(void);
X extern void config_sun3(void);
X extern void config_apollo(void);
+extern void config_mvme147(void);
X extern void config_mvme16x(void);
X extern void config_bvme6000(void);
X extern void config_hp300(void);
+extern void config_q40(void);
+extern void config_sun3x(void);
X 
X #define MASK_256K 0xfffc0000
X 
@@ -149,6 +169,8 @@
X 		    unknown = atari_parse_bootinfo(record);
X 		else if (MACH_IS_MAC)
X 		    unknown = mac_parse_bootinfo(record);
+		else if (MACH_IS_Q40)
+		    unknown = q40_parse_bootinfo(record);
X 		else
X 		    unknown = 1;
X 	}
@@ -258,6 +280,11 @@
X 	    	config_apollo();
X 	    	break;
X #endif
+#ifdef CONFIG_MVME147
+	    case MACH_MVME147:
+	    	config_mvme147();
+	    	break;
+#endif
X #ifdef CONFIG_MVME16x
X 	    case MACH_MVME16x:
X 	    	config_mvme16x();
@@ -273,6 +300,16 @@
X 		config_hp300();
X 		break;
X #endif
+#ifdef CONFIG_Q40
+	    case MACH_Q40:
+	        config_q40();
+		break;
+#endif
+#ifdef CONFIG_SUN3X
+	    case MACH_SUN3X:
+		config_sun3x();
+		break;
+#endif
X 	    default:
X 		panic ("No configuration setup");
X 	}
@@ -384,7 +421,52 @@
X     return(len);
X }
X 
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_SERIAL) || defined(M68K_SERIAL)
+int rs_init(void)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return serial_rs_init();
+#endif
+#ifdef M68K_SERIAL  
+    return m68k_rs_init();
+#endif
+}
+int register_serial(struct serial_struct *p)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return serial_register_serial(p);
+#endif
+#ifdef M68K_SERIAL
+  return m68k_register_serial(p);
+#endif
+}
+void unregister_serial(int i)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    serial_unregister_serial(i);
+#endif
+#ifdef M68K_SERIAL
+  m68k_unregister_serial(i);
+#endif
+}
+#ifdef CONFIG_SERIAL_CONSOLE
+long serial_console_init(long kmem_start, long kmem_end)
+{
+#ifdef CONFIG_SERIAL
+  if (MACH_IS_Q40)
+    return ser_console_init(kmem_start, kmem_end);
+#endif
+#if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE)
+  return m68k_serial_console_init(kmem_start, kmem_end);
+#endif
+}
+#endif
+#endif
+
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
X __initfunc(void floppy_setup(char *str, int *ints))
X {
X 	if (mach_floppy_setup)
@@ -399,7 +481,7 @@
X #endif
X 
X /* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+__initfunc(void kbd_reset_setup(char *str, int *ints))
X {
X }
X 
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- v2.2.7/linux/arch/m68k/kernel/time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/m68k/kernel/time.c	Tue May 11 09:57:14 1999
@@ -200,5 +200,5 @@
X 	time_status |= STA_UNSYNC;
X 	time_maxerror = NTP_PHASE_LIMIT;
X 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	write_unlock_irq(&xtime_lock);
X }
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/lib/semaphore.S linux/arch/m68k/lib/semaphore.S
--- v2.2.7/linux/arch/m68k/lib/semaphore.S	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/lib/semaphore.S	Tue May 11 09:57:14 1999
@@ -32,6 +32,16 @@
X 	movel (%sp)+,%a0
X 	rts
X 
+ENTRY(__down_failed_trylock)
+	movel %a0,-(%sp)
+	movel %d1,-(%sp)
+	movel %a1,-(%sp)
+	jbsr SYMBOL_NAME(__down_trylock)
+	movel (%sp)+,%a1
+	movel (%sp)+,%d1
+	movel (%sp)+,%a0
+	rts
+
X ENTRY(__up_wakeup)
X 	moveml %a0/%d0/%d1,-(%sp)
X 	movel %a1,-(%sp)
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.2.7/linux/arch/m68k/mm/init.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/mm/init.c	Tue May 11 09:57:14 1999
@@ -123,7 +123,7 @@
X unsigned long mm_cachebits = 0;
X #endif
X 
-static pte_t *__init kernel_page_table(unsigned long *memavailp)
+__initfunc(static pte_t * kernel_page_table(unsigned long *memavailp))
X {
X 	pte_t *ptablep;
X 
@@ -140,15 +140,19 @@
X 
X static pmd_t *last_pgtable __initdata = NULL;
X 
-static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
+__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp))
X {
X 	if (!last_pgtable) {
X 		unsigned long pmd, last;
X 		int i;
X 
+		/* Find the last ptr table that was used in head.S and
+		 * reuse the remaining space in that page for further
+		 * ptr tables.
+		 */
X 		last = (unsigned long)kernel_pg_dir;
X 		for (i = 0; i < PTRS_PER_PGD; i++) {
-			if (!pgd_val(kernel_pg_dir[i]))
+			if (!pgd_present(kernel_pg_dir[i]))
X 				continue;
X 			pmd = pgd_page(kernel_pg_dir[i]);
X 			if (pmd > last)
@@ -175,8 +179,8 @@
X 	return last_pgtable;
X }
X 
-static unsigned long __init
-map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, long size, unsigned long *memavailp))
X {
X #define PTRTREESIZE (256*1024)
X #define ROOTTREESIZE (32*1024*1024)
@@ -282,8 +286,8 @@
X  * paging_init() continues the virtual memory environment setup which
X  * was begun by the code in arch/head.S.
X  */
-unsigned long __init paging_init(unsigned long start_mem,
-				 unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem,
+				     unsigned long end_mem))
X {
X 	int chunk;
X 	unsigned long mem_avail = 0;
@@ -392,7 +396,7 @@
X 	return PAGE_ALIGN(free_area_init(start_mem, end_mem));
X }
X 
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
X {
X 	int codepages = 0;
X 	int datapages = 0;
@@ -443,7 +447,7 @@
X 	/* insert pointer tables allocated so far into the tablelist */
X 	init_pointer_table((unsigned long)kernel_pg_dir);
X 	for (i = 0; i < PTRS_PER_PGD; i++) {
-		if (pgd_val(kernel_pg_dir[i]))
+		if (pgd_present(kernel_pg_dir[i]))
X 			init_pointer_table(pgd_page(kernel_pg_dir[i]));
X 	}
X 
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c
--- v2.2.7/linux/arch/m68k/mm/kmap.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/mm/kmap.c	Tue May 11 09:57:14 1999
@@ -116,6 +116,14 @@
X 	if (!size || size > physaddr + size)
X 		return NULL;
X 
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA) {
+		if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+		    && (cacheflag == IOMAP_NOCACHE_SER))
+			return (void *)physaddr;
+	}
+#endif
+
X #ifdef DEBUG
X 	printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
X #endif
@@ -174,7 +182,7 @@
X 		}
X 	}
X 
-	while (size > 0) {
+	while ((long)size > 0) {
X #ifdef DEBUG
X 		if (!(virtaddr & (PTRTREESIZE-1)))
X 			printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
@@ -187,7 +195,7 @@
X 		}
X 
X 		if (CPU_IS_020_OR_030) {
-			pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr;
+			pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
X 			physaddr += PTRTREESIZE;
X 			virtaddr += PTRTREESIZE;
X 			size -= PTRTREESIZE;
@@ -217,7 +225,14 @@
X  */
X void iounmap(void *addr)
X {
+#ifdef CONFIG_AMIGA
+	if ((!MACH_IS_AMIGA) ||
+	    (((unsigned long)addr < 0x40000000) ||
+	     ((unsigned long)addr > 0x60000000)))
+			free_io_area(addr);
+#else
X 	free_io_area(addr);
+#endif
X }
X 
X /*
@@ -232,7 +247,7 @@
X 	pmd_t *pmd_dir;
X 	pte_t *pte_dir;
X 
-	while (size > 0) {
+	while ((long)size > 0) {
X 		pgd_dir = pgd_offset_k(virtaddr);
X 		if (pgd_bad(*pgd_dir)) {
X 			printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -242,7 +257,7 @@
X 		pmd_dir = pmd_offset(pgd_dir, virtaddr);
X 
X 		if (CPU_IS_020_OR_030) {
-			int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+			int pmd_off = (virtaddr/PTRTREESIZE) & 15;
X 
X 			if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
X 				pmd_dir->pmd[pmd_off] = 0;
@@ -308,7 +323,7 @@
X 		}
X 	}
X 
-	while (size > 0) {
+	while ((long)size > 0) {
X 		pgd_dir = pgd_offset_k(virtaddr);
X 		if (pgd_bad(*pgd_dir)) {
X 			printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -318,7 +333,7 @@
X 		pmd_dir = pmd_offset(pgd_dir, virtaddr);
X 
X 		if (CPU_IS_020_OR_030) {
-			int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+			int pmd_off = (virtaddr/PTRTREESIZE) & 15;
X 
X 			if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
X 				pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.2.7/linux/arch/m68k/mm/memory.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/mm/memory.c	Tue May 11 09:57:14 1999
@@ -11,6 +11,7 @@
X #include <linux/types.h>
X #include <linux/malloc.h>
X #include <linux/init.h>
+#include <linux/pagemap.h>
X 
X #include <asm/setup.h>
X #include <asm/segment.h>
@@ -93,12 +94,11 @@
X static ptable_desc ptable_list = { &ptable_list, &ptable_list };
X 
X #define PD_MARKBITS(dp) (*(unsigned char *)&(dp)->offset)
-#define PD_PAGE(dp) (PAGE_OFFSET + ((dp)->map_nr << PAGE_SHIFT))
X #define PAGE_PD(page) ((ptable_desc *)&mem_map[MAP_NR(page)])
X 
X #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
X 
-void __init init_pointer_table(unsigned long ptable)
+__initfunc(void init_pointer_table(unsigned long ptable))
X {
X 	ptable_desc *dp;
X 	unsigned long page = ptable & PAGE_MASK;
@@ -166,7 +166,7 @@
X 		(dp->next = last->next)->prev = dp;
X 		(dp->prev = last)->next = dp;
X 	}
-	return (pmd_t *) (PD_PAGE(dp) + off);
+	return (pmd_t *) (page_address(dp) + off);
X }
X 
X int free_pointer_table (pmd_t *ptable)
@@ -215,8 +215,8 @@
X 	/* function code match? */
X 	base = (regval >> 4) & 7;
X 	mask = ~(regval & 7);
-	if ((SUPER_DATA & mask) != (base & mask))
-	    return( 0 );
+	if (((SUPER_DATA ^ base) & mask) != 0)
+	    return 0;
X     }
X     else {
X 	/* must not be user-only */
@@ -226,8 +226,8 @@
X 
X     /* address match? */
X     base = regval & 0xff000000;
-    mask = ~((regval << 8) & 0xff000000);
-    return( (vaddr & mask) == (base & mask) );
+    mask = ~(regval << 8) & 0xff000000;
+    return ((vaddr ^ base) & mask) == 0;
X }
X 
X #ifndef CONFIG_SINGLE_MEMORY_CHUNK
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mvme147/147ints.c linux/arch/m68k/mvme147/147ints.c
--- v2.2.7/linux/arch/m68k/mvme147/147ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme147/147ints.c	Tue May 11 09:57:14 1999
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 06'
echo 'File patch-2.2.8 is continued in part 07'
echo 07 > _shar_seq_.tmp
#!/bin/sh
# this is part 07 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 07; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
@@ -0,0 +1,142 @@
+/*
+ * arch/m68k/mvme147/147ints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [ric...@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+	const char	*devname;
+	unsigned	count;
+} irq_tab[256];
+
+/*
+ * void mvme147_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ (void)
+{
+	int i;
+
+	for (i = 0; i < 256; i++) {
+		irq_tab[i].handler = mvme147_defhand;
+		irq_tab[i].flags = IRQ_FLG_STD;
+		irq_tab[i].dev_id = NULL;
+		irq_tab[i].devname = NULL;
+		irq_tab[i].count = 0;
+	}
+}
+
+int mvme147_request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+	if (irq > 255) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+	if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+		if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_tab[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_tab[irq].devname);
+			return -EBUSY;
+		}
+	}
+	irq_tab[irq].handler = handler;
+	irq_tab[irq].flags   = flags;
+	irq_tab[irq].dev_id  = dev_id;
+	irq_tab[irq].devname = devname;
+	return 0;
+}
+
+void mvme147_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq > 255) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
+	if (irq_tab[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_tab[irq].devname);
+
+	irq_tab[irq].handler = mvme147_defhand;
+	irq_tab[irq].flags   = IRQ_FLG_STD;
+	irq_tab[irq].dev_id  = NULL;
+	irq_tab[irq].devname = NULL;
+}
+
+void mvme147_process_int (unsigned long vec, struct pt_regs *fp)
+{
+	if (vec > 255)
+		printk ("mvme147_process_int: Illegal vector %ld\n", vec);
+	else
+	{
+		irq_tab[vec].count++;
+		irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+	}
+}
+
+int mvme147_get_irq_list (char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i < 256; i++) {
+		if (irq_tab[i].count)
+			len += sprintf (buf+len, "Vec 0x%02x: %8d  %s\n",
+			    i, irq_tab[i].count,
+			    irq_tab[i].devname ? irq_tab[i].devname : "free");
+	}
+	return len;
+}
+
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+	printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void mvme147_enable_irq (unsigned int irq)
+{
+}
+
+
+void mvme147_disable_irq (unsigned int irq)
+{
+}
+
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mvme147/Makefile linux/arch/m68k/mvme147/Makefile
--- v2.2.7/linux/arch/m68k/mvme147/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme147/Makefile	Tue May 11 09:57:14 1999
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/mvme147 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+O_TARGET := mvme147.o
+O_OBJS   := config.o 147ints.o
+
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- v2.2.7/linux/arch/m68k/mvme147/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme147/config.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,240 @@
+/*
+ *  arch/m68k/mvme147/config.c
+ *
+ *  Copyright (C) 1996 Dave Frascone [ch...@mindspring.com]
+ *  Cloned from        Richard Hirst [ric...@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/mvme147hw.h>
+
+
+extern void mvme147_process_int (int level, struct pt_regs *regs);
+extern void mvme147_init_IRQ (void);
+extern void mvme147_free_irq (unsigned int, void *);
+extern int  mvme147_get_irq_list (char *);
+extern void mvme147_enable_irq (unsigned int);
+extern void mvme147_disable_irq (unsigned int);
+static void mvme147_get_model(char *model);
+static int  mvme147_get_hardware_list(char *buffer);
+extern int mvme147_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void mvme147_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int mvme147_keyb_init(void);
+extern int mvme147_kbdrate (struct kbd_repeat *);
+extern unsigned long mvme147_gettimeoffset (void);
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int mvme147_hwclk (int, struct hwclk_time *);
+extern int mvme147_set_clock_mmss (unsigned long);
+extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev);
+extern void mvme147_reset (void);
+extern void mvme147_waitbut(void);
+
+
+static int bcd2int (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme147_process_int() */
+
+void (*tick_handler)(int, void *, struct pt_regs *);
+
+
+int mvme147_kbdrate (struct kbd_repeat *k)
+{
+	return 0;
+}
+
+void mvme147_reset()
+{
+	printk ("\r\n\nCalled mvme147_reset\r\n");
+	m147_pcc->watchdog = 0x0a;	/* Clear timer */
+	m147_pcc->watchdog = 0xa5;	/* Enable watchdog - 100ms to reset */
+	while (1)
+		;
+}
+
+static void mvme147_get_model(char *model)
+{
+	sprintf(model, "Motorola MVME147");
+}
+
+
+static int mvme147_get_hardware_list(char *buffer)
+{
+	*buffer = '\0';
+
+	return 0;
+}
+
+
+__initfunc(void config_mvme147(void))
+{
+	mach_sched_init		= mvme147_sched_init;
+	mach_keyb_init		= mvme147_keyb_init;
+	mach_kbdrate		= mvme147_kbdrate;
+	mach_init_IRQ		= mvme147_init_IRQ;
+	mach_gettimeoffset	= mvme147_gettimeoffset;
+	mach_gettod		= mvme147_gettod;
+	mach_hwclk		= mvme147_hwclk;
+	mach_set_clock_mmss	= mvme147_set_clock_mmss;
+	mach_reset		= mvme147_reset;
+	mach_free_irq		= mvme147_free_irq;
+	mach_process_int	= mvme147_process_int;
+	mach_get_irq_list	= mvme147_get_irq_list;
+	mach_request_irq	= mvme147_request_irq;
+	enable_irq		= mvme147_enable_irq;
+	disable_irq		= mvme147_disable_irq;
+	mach_get_model		= mvme147_get_model;
+	mach_get_hardware_list	= mvme147_get_hardware_list;
+}
+
+
+/* Using pcc tick timer 1 */
+
+static void mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  
+	m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;   
+	tick_handler(irq, dev_id, fp);
+}
+
+
+void mvme147_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+	tick_handler = timer_routine;
+	request_irq (PCC_IRQ_TIMER1, mvme147_timer_int, 
+		IRQ_FLG_REPLACE, "timer 1", NULL);
+	
+	/* Init the clock with a value */
+	/* our clock goes off every 6.25us */
+	m147_pcc->t1_preload = PCC_TIMER_PRELOAD;
+	m147_pcc->t1_cntrl = 0x0;   	/* clear timer */
+	m147_pcc->t1_cntrl = 0x3; 	/* start timer */
+	m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;  /* clear pending ints */
+	m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;   
+}
+
+/* This is always executed with interrupts disabled.  */
+/* XXX There are race hazards in this code XXX */
+unsigned long mvme147_gettimeoffset (void)
+{
+	volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
+	unsigned short n;
+
+	n = *cp;
+	while (n != *cp)
+		n = *cp;
+
+	n -= PCC_TIMER_PRELOAD;
+	return (unsigned long)n * 25 / 4;
+}
+
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+	m147_rtc->ctrl = RTC_READ;
+	*year = bcd2int (m147_rtc->bcd_year);
+	*mon = bcd2int (m147_rtc->bcd_mth);
+	*day = bcd2int (m147_rtc->bcd_dom);
+	*hour = bcd2int (m147_rtc->bcd_hr);
+	*min = bcd2int (m147_rtc->bcd_min);
+	*sec = bcd2int (m147_rtc->bcd_sec);
+	m147_rtc->ctrl = 0;
+}
+
+static int bcd2int (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
+}
+
+int mvme147_hwclk(int op, struct hwclk_time *t)
+{
+	return 0;
+}
+
+int mvme147_set_clock_mmss (unsigned long nowtime)
+{
+	return 0;
+}
+
+int mvme147_keyb_init (void)
+{
+	return 0;
+}
+
+/*-------------------  Serial console stuff ------------------------*/
+
+void m147_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void mvme147_init_console_port (struct console *co, int cflag)
+{
+	co->write = m147_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+	int n;
+	volatile int trash;
+
+	for (n = 0; n < 20; n++)
+		trash = n;
+}
+
+static void scc_write (char ch)
+{
+	volatile char *p = (volatile char *)M147_SCC_A_ADDR;
+
+	do {
+		scc_delay();
+	}
+	while (!(*p & 4));
+	scc_delay();
+	*p = 8;
+	scc_delay();
+	*p = ch;
+}
+
+
+void m147_scc_write (struct console *co, const char *str, unsigned count)
+{
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	while (count--)
+	{
+		if (*str == '\n')
+			scc_write ('\r');
+		scc_write (*str++);
+	}
+	restore_flags(flags);
+}
+
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- v2.2.7/linux/arch/m68k/mvme16x/config.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/mvme16x/config.c	Tue May 11 09:57:14 1999
@@ -335,10 +335,10 @@
X static void scc_delay (void)
X {
X 	int n;
-	char i;
+	volatile int trash;
X 
X 	for (n = 0; n < 20; n++)
-		i = *(volatile char *)0;
+		trash = n;
X }
X 
X static void scc_write (char ch)
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/q40/Makefile linux/arch/m68k/q40/Makefile
--- v2.2.7/linux/arch/m68k/q40/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/Makefile	Tue May 11 09:57:14 1999
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/q40 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := q40.o
+O_OBJS   := config.o q40ints.o 
+
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/q40/README linux/arch/m68k/q40/README
--- v2.2.7/linux/arch/m68k/q40/README	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/README	Tue May 11 09:57:14 1999
@@ -0,0 +1,121 @@
+Linux for the Q40
+=================
+
+You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
+some up to date information. Booter and other tools will be also
+available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
+and mirrors.
+
+Hints to documentation usually refer to the linux source tree in
+/usr/src/linux unless URL given.
+
+It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is 
+not yet implemented - do not try it! (See below)
+
+For a list of kernel commandline options read the documentation for the
+particular device drivers.
+
+The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
+When something blocks interrupts (HD) it will loose some of them, so far 
+this is not known to have caused any data loss. On hihgly loaded systems
+it can make the floppy very slow. Other Q40 OS' simply poll the floppy
+for this reason - something that can't be done in Linux.
+Only possible cure is getting a 82072 contoler with fifo instead of 
+the 8272A
+
+drivers used by the Q40, appart from the very obvious (console etc.):
+	drivers/char/q40_keyb.c		# use PC keymaps for national keyboards
+		     serial.c		# normal PC driver - any speed
+	             lp.c		# printer driver
+		char/joystick/*		# most of this should work
+	        block/q40ide.c		# startup for ide
+		      ide*		# see Documentation/ide.txt
+		      floppy.c		# normal PC driver, DMA emu in asm/floppy.h
+					# and arch/m68k/kernel/entry.S
+					# see drivers/block/README.fd
+		video/q40fb.c
+		misc/parport_pc.c
+
+Various other PC drivers can be enabled simply by adding them to 
+arch/m68k/config.in, especially 8 bit devices should be without any
+problems. For cards using 16bit io/mem more care is required, like 
+checking byteorder issues, hacking memcpy_*_io etc.
+
+
+Debugging
+=========
+
+Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM, 
+preceded by the booter signature. This is a trace just in case something 
+went wrong during earliest setup stages. 
+*Changed* to preserve SRAM contents by default, this is only done when 
+requested - SRAM must start with '%LX$' signature to do this. '-d' option 
+to 'lxx' loader enables this.
+
+SRAM can also be used as additional console device, use debug=mem.
+This will save kernel startup msgs into SRAM, the screen will display 
+only the penguin - and shell prompt if it gets that far..
+
+Serial console works and can also be used for debugging, provided serial
+initialisation works.
+
+Most problems seem to be caused by fawlty or badly configured io-cards or 
+harddrives anyway..there are so many things that can go wrong here.
+Make sure to configure the parallel port as SPP for first testing..the
+Q40 may have trouble with parallel interrupts.
+
+
+Q40 Hardware Description
+========================
+
+This is just an overview, see asm-m68k/* for details ask if you have any 
+questions.
+
+The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style
+keyboard interface, 1 Programmable LED, 2 8bit DACs and up to 1MB ROM, 1MB
+shadow ROM.
+
+Most interfacing like floppy, hd, serial, parallel ports is done via ISA 
+slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate 
+regions of the memory.
+The main interrupt register IIRQ_REG will indicate whether an IRQ was internal 
+or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs.
+
+The Q40 custom chip is programmable to provide 2 periodic timers:
+	- 50 or 200 Hz - level 2,  !!THIS CANT BE DISABLED!!
+	- 10 or 20 KHz - level 4 (and possibly 6 - hardware decoding..)
+
+Linux uses the 200 Hz interrupt for timer and beep by default.
+
+
+Interrupts
+==========
+
+q40 master chip handles only level triggered interrupts :-((
+further limitation is no disabling etc. Unless someone finds 
+some ingenious clue this means autoprobing will never work.
+Parallel port interrupts cause most trouble..
+
+IRQ sharing is not yet implemented.
+
+
+Keyboard
+========
+
+q40 receives AT make/break codes from the keyboard, these are translated to
+the PC scancodes x86 Linux uses. So by theory every national keyboard should
+work just by loading the apropriate x86 keytable - see any national-HOWTO.
+
+Unfortunately the AT->PC translation isn't quite trivial and even worse, my 
+documentation of it is absolutely minimal - thus some exotic keys may not 
+behave exactly as expected.
+
+There is still hope that it can be fixed completely though. If you encounter 
+problems, email me idealy this:
+	- exact keypress/release sequence
+	- 'showkey -s' run on q40, non-X session
+	- 'showkey -s' run on a PC, non-X session
+	- AT codes as displayed by the q40 debuging ROM
+btw if the showkey output from PC and Q40 doesn't differ then you have some
+classic configuration problem - don't send me anything in this case
+
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.2.7/linux/arch/m68k/q40/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/config.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,425 @@
+/*
+ *  arch/m68k/q40/config.c
+ *
+ * originally based on:
+ *
+ *  linux/bvme/config.c
+ *
+ *  Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/q40_master.h>
+#include <asm/keyboard.h>
+
+extern void fd_floppy_eject(void);
+extern void fd_floppy_setup(char *str, int *ints);
+
+extern void q40_process_int (int level, struct pt_regs *regs);
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+extern void q40_init_IRQ (void);
+extern void q40_free_irq (unsigned int, void *);
+extern int  q40_get_irq_list (char *);
+extern void q40_enable_irq (unsigned int);
+extern void q40_disable_irq (unsigned int);
+static void q40_get_model(char *model);
+static int  q40_get_hardware_list(char *buffer);
+extern int  q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int  q40_keyb_init(void);
+extern int  q40_kbdrate (struct kbd_repeat *);
+extern unsigned long q40_gettimeoffset (void);
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int q40_hwclk (int, struct hwclk_time *);
+extern int q40_set_clock_mmss (unsigned long);
+extern void q40_reset (void);
+extern void q40_waitbut(void);
+void q40_set_vectors (void);
+extern void (*kd_mksound)(unsigned int, unsigned int);
+void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
+
+extern char *saved_command_line;
+extern char m68k_debug_device[];
+static void q40_mem_console_write(struct console *co, const char *b,
+				    unsigned int count);
+
+static int ql_ticks=0;
+static int sound_ticks=0;
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+static int q40_wait_key(struct console *co){return 0;}
+static struct console q40_console_driver = {
+	"debug",
+	NULL,			/* write */
+	NULL,			/* read */
+	NULL,			/* device */
+	q40_wait_key,		/* wait_key */
+	NULL,			/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c */
+
+/* static void (*tick_handler)(int, void *, struct pt_regs *); */
+
+
+/* early debugging function:*/
+extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
+static int _cpleft;
+
+static void q40_mem_console_write(struct console *co, const char *s,
+				  unsigned int count)
+{
+  char *p=(char *)s;
+
+  if (count<_cpleft)
+    while (count-- >0){
+      *q40_mem_cptr=*p++;
+      q40_mem_cptr+=4;
+      _cpleft--;
+    }
+}
+#if 0
+void printq40(char *str)
+{
+  int l=strlen(str);
+  char *p=q40_mem_cptr;
+
+  while (l-- >0 && _cpleft-- >0)
+    {
+      *p=*str++;
+      p+=4;
+    }
+  q40_mem_cptr=p;
+}
+#endif
+
+#if 0
+int q40_kbdrate (struct kbd_repeat *k)
+{
+	return 0;
+}
+#endif
+
+void q40_reset()
+{
+
+	printk ("\n\n*******************************************\n"
+                     "Called q40_reset : press the RESET button!! \n");
+	printk(     "*******************************************\n");
+
+	while(1)
+		;
+}
+
+static void q40_get_model(char *model)
+{
+    sprintf(model, "Q40");
+}
+
+
+/* No hardware options on Q40? */
+
+static int q40_get_hardware_list(char *buffer)
+{
+    *buffer = '\0';
+    return 0;
+}
+
+
+__initfunc(void config_q40(void))
+{
+    mach_sched_init      = q40_sched_init;           /* ok */
+    /*mach_kbdrate         = q40_kbdrate;*/          /* unneeded ?*/
+    mach_keyb_init       = q40_keyb_init;            /* OK */
+    mach_init_IRQ        = q40_init_IRQ;   
+    mach_gettimeoffset   = q40_gettimeoffset; 
+    mach_gettod  	 = q40_gettod;
+    mach_hwclk           = q40_hwclk; 
+    mach_set_clock_mmss	 = q40_set_clock_mmss;
+/*  mach_mksound         = q40_mksound; */
+    mach_reset		 = q40_reset;           /* use reset button instead !*/
+    mach_free_irq	 = q40_free_irq; 
+    mach_process_int	 = q40_process_int;
+    mach_get_irq_list	 = q40_get_irq_list;
+    mach_request_irq	 = q40_request_irq;
+    enable_irq		 = q40_enable_irq;
+    disable_irq          = q40_disable_irq;
+    mach_default_handler = &q40_sys_default_handler;
+    mach_get_model       = q40_get_model; /* no use..*/
+    mach_get_hardware_list = q40_get_hardware_list; /* no use */
+    kd_mksound             = q40_mksound;
+    /*mach_kbd_leds        = q40kbd_leds;*/
+#ifdef CONFIG_MAGIC_SYSRQ
+    mach_sysrq_key       = 0x54;
+#endif
+    conswitchp = &dummy_con;
+#ifdef CONFIG_BLK_DEV_FD
+    mach_floppy_setup    = fd_floppy_setup;
+    mach_floppy_eject    = fd_floppy_eject;
+    /**/
+#endif
+
+    mach_max_dma_address = 0;   /* no DMA at all */
+
+
+/* userfull for early debuging stages writes kernel messages into SRAM */
+
+    if (!strncmp( m68k_debug_device,"mem",3 ))
+      {
+	/*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+	_cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
+	q40_console_driver.write = q40_mem_console_write;
+	register_console(&q40_console_driver);
+      }
+}
+
+
+int q40_parse_bootinfo(const struct bi_record *rec)
+{
+  return 1;  /* unknown */
+}
+
+#define DAC_LEFT  ((unsigned char *)0xff008000)
+#define DAC_RIGHT ((unsigned char *)0xff008004)
+void q40_mksound(unsigned int hz, unsigned int ticks)
+{
+  /* for now ignore hz, except that hz==0 switches off sound */
+  /* simply alternate the ampl 0-255-0-.. at 200Hz */
+  if (hz==0)
+    {
+      if (sound_ticks)
+	sound_ticks=1; /* atomic - no irq spinlock used */
+
+      *DAC_LEFT=0;
+      *DAC_RIGHT=0;
+
+      return;
+    }
+  /* sound itself is done in q40_timer_int */
+  if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
+  sound_ticks=ticks<<1;
+}
+
+static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+
+static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if (HZ==10000)
+    master_outb(-1,SAMPLE_CLEAR_REG);
+#else /* must be 50 or 100 */
+    master_outb(-1,FRAME_CLEAR_REG);
+#endif
+
+#if (HZ==100)
+    ql_ticks = ql_ticks ? 0 : 1;
+    if (sound_ticks)
+      {
+	unsigned char sval=(sound_ticks & 1) ? 0 : 255;
+	sound_ticks--;
+	*DAC_LEFT=sval;
+	*DAC_RIGHT=sval;
+      }
+    if (ql_ticks) return;
+#endif
+    q40_timer_routine(irq, dev_id, fp);
+}
+
+
+void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+    int timer_irq;
+
+    q40_timer_routine = timer_routine;
+
+#if (HZ==10000)
+    timer_irq=Q40_IRQ_TIMER;
+#else
+    timer_irq=Q40_IRQ_FRAME;
+#endif
+
+    /*printk("registering sched/timer IRQ %d\n", timer_irq);*/
+
+    if (request_irq(timer_irq, q40_timer_int, 0,
+				"timer", q40_timer_int))
+	panic ("Couldn't register timer int");
+
+#if (HZ==10000)
+    master_outb(SAMPLE_LOW,SAMPLE_RATE_REG);
+    master_outb(-1,SAMPLE_CLEAR_REG);
+    master_outb(1,SAMPLE_ENABLE_REG);
+#else
+    master_outb(-1,FRAME_CLEAR_REG);   /* not necessary ? */
+#if (HZ==100)
+    master_outb( 1,FRAME_RATE_REG);
+#endif
+#endif
+}
+
+
+unsigned long q40_gettimeoffset (void)
+{
+#if (HZ==100)
+    return 5000*(ql_ticks!=0);
+#else
+    return 0;
+#endif
+}
+
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+	RTC_CTRL |= RTC_READ;
+	*year = bcd2bin (RTC_YEAR);
+	*mon = bcd2bin (RTC_MNTH)-1;
+	*day = bcd2bin (RTC_DATE);
+	*hour = bcd2bin (RTC_HOUR);
+	*min = bcd2bin (RTC_MINS);
+	*sec = bcd2bin (RTC_SECS);
+	RTC_CTRL &= ~(RTC_READ);
+
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+	return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ *  struct hwclk_time {
+ *         unsigned        sec;       0..59
+ *         unsigned        min;       0..59
+ *         unsigned        hour;      0..23
+ *         unsigned        day;       1..31
+ *         unsigned        mon;       0..11
+ *         unsigned        year;      00...
+ *         int             wday;      0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int q40_hwclk(int op, struct hwclk_time *t)
+{
+        if (op)
+	{	/* Write.... */
+	        RTC_CTRL |= RTC_WRITE;
+
+		RTC_SECS = bin2bcd(t->sec);
+		RTC_MINS = bin2bcd(t->min);
+		RTC_HOUR = bin2bcd(t->hour);
+		RTC_DATE = bin2bcd(t->day);
+		RTC_MNTH = bin2bcd(t->mon + 1);
+		RTC_YEAR = bin2bcd(t->year%100);
+		if (t->wday >= 0)
+			RTC_DOW = bin2bcd(t->wday+1);
+
+	        RTC_CTRL &= ~(RTC_WRITE);
+	}
+	else
+	{	/* Read....  */
+	  RTC_CTRL |= RTC_READ;
+
+	  t->year = bcd2bin (RTC_YEAR);
+	  t->mon  = bcd2bin (RTC_MNTH)-1;
+	  t->day  = bcd2bin (RTC_DATE);
+	  t->hour = bcd2bin (RTC_HOUR);
+	  t->min  = bcd2bin (RTC_MINS);
+	  t->sec  = bcd2bin (RTC_SECS);
+
+	  RTC_CTRL &= ~(RTC_READ);
+	  
+	  if (t->year < 70)
+	    t->year += 100;
+	  t->wday = bcd2bin(RTC_DOW)-1;
+
+	}
+
+	return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'.  Fail if
+ * clock is out by > 30 minutes.  Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int q40_set_clock_mmss (unsigned long nowtime)
+{
+	int retval = 0;
+	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+	int rtc_minutes;
+
+
+	rtc_minutes = bcd2bin (RTC_MINS);
+
+	if ((rtc_minutes < real_minutes
+		? real_minutes - rtc_minutes
+			: rtc_minutes - real_minutes) < 30)
+	{	   
+	        RTC_CTRL |= RTC_WRITE;
+		RTC_MINS = bin2bcd(real_minutes);
+		RTC_SECS = bin2bcd(real_seconds);
+		RTC_CTRL &= ~(RTC_WRITE);
+	}
+	else
+		retval = -1;
+
+
+	return retval;
+}
+
+extern void q40kbd_init_hw(void);
+
+int q40_keyb_init (void)
+{
+        q40kbd_init_hw();
+	return 0;
+}
+
+#if 0
+/* dummy to cause */
+void q40_slow_io()
+{
+  return;
+}
+#endif
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/q40/q40ints.c linux/arch/m68k/q40/q40ints.c
--- v2.2.7/linux/arch/m68k/q40/q40ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/q40/q40ints.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,347 @@
+/*
+ * arch/m68k/q40/q40ints.c
+ *
+ * Copyright (C) 1999 Richard Zidlicky
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * losely based on bvme6000ints.c
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+#include <asm/q40_master.h>
+#include <asm/q40ints.h>
+
+/* 
+ * Q40 IRQs are defined as follows: 
+ *            3,4,5,6,7,10,11,14,15 : ISA dev IRQs
+ *            16-31: reserved
+ *            32   : keyboard int
+ *            33   : frame int (50 Hz periodic timer)
+ *            34   : sample int (10/20 KHz periodic timer)
+ *          
+*/
+
+extern int ints_inited;
+
+
+void q40_irq2_handler (int, void *, struct pt_regs *fp);
+
+
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+#define DEVNAME_SIZE 24
+
+static struct {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+        char	        devname[DEVNAME_SIZE];
+	unsigned	count;
+} irq_tab[Q40_IRQ_MAX+1];
+
+/*
+ * void q40_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the q40 IRQ handling routines.
+ */
+
+void q40_init_IRQ (void)
+{
+	int i;
+
+	for (i = 0; i <= Q40_IRQ_MAX; i++) {
+		irq_tab[i].handler = q40_defhand;
+		irq_tab[i].flags = IRQ_FLG_STD;
+		irq_tab[i].dev_id = NULL;
+		irq_tab[i].devname[0] = 0;
+		irq_tab[i].count = 0;
+	}
+
+	/* setup handler for ISA ints */
+	sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL);
+
+	/* now enable some ints.. */
+
+#if 0  /* has been abandoned */
+	master_outb(1,SER_ENABLE_REG);
+#endif
+	master_outb(1,EXT_ENABLE_REG);
+
+	/* would be spurious ints by now, q40kbd_init_hw() does that */
+	master_outb(0,KEY_IRQ_ENABLE_REG);
+}
+
+int q40_request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+  /*printk("q40_request_irq %d, %s\n",irq,devname);*/
+
+	if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+
+	/* test for ISA ints not implemented by HW */
+	if (irq<15) 
+	  {
+	    switch (irq){
+	    case 1: case 2: case 8: case 9:
+	    case 12: case 13:
+	      printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
+	      return -ENXIO;
+	    default:
+	    }
+	  }
+
+	if (irq<Q40_IRQ_TIMER)
+	  {
+	    if (irq==11) {
+	      printk("warning IRQ 10 and 11 not distinguishable\n");
+	      irq=10;
+	    }
+	    if (!(irq_tab[irq].flags & IRQ_FLG_STD)) 
+	      {
+		if (irq_tab[irq].flags & IRQ_FLG_LOCK) 
+		  {
+		    printk("%s: IRQ %d from %s is not replaceable\n",
+			   __FUNCTION__, irq, irq_tab[irq].devname);
+		    return -EBUSY;
+		  }
+		if (flags & IRQ_FLG_REPLACE) 
+		  {
+		    printk("%s: %s can't replace IRQ %d from %s\n",
+			   __FUNCTION__, devname, irq, irq_tab[irq].devname);
+		    return -EBUSY;
+		  }
+	      }
+	    /*printk("IRQ %d set to handler %p\n",irq,handler);*/
+	    irq_tab[irq].handler = handler;
+	    irq_tab[irq].flags   = flags;
+	    irq_tab[irq].dev_id  = dev_id;
+	    strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
+	    return 0;
+	  }
+	else {
+	  /* Q40_IRQ_TIMER :somewhat special actions required here ..*/
+	  sys_request_irq(4,handler,flags,devname,dev_id);
+	  sys_request_irq(6,handler,flags,devname,dev_id);
+	  return 0;
+	}
+}
+
+void q40_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+		printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
+		return;
+	}
+
+	/* test for ISA ints not implemented by HW */
+	if (irq<15) {
+	  switch (irq){
+	  case 1: case 2: case 8: case 9:
+	  case 12: case 13:
+	        printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+		return;
+	  default:
+		  }
+	}
+	
+	if (irq<Q40_IRQ_TIMER){
+	  if (irq==11) irq=10;
+	  if (irq_tab[irq].dev_id != dev_id)
+	    printk("%s: Removing probably wrong IRQ %d from %s\n",
+		   __FUNCTION__, irq, irq_tab[irq].devname);
+	  
+	  irq_tab[irq].handler = q40_defhand;
+	  irq_tab[irq].flags   = IRQ_FLG_STD;
+	  irq_tab[irq].dev_id  = NULL;
+	  /* irq_tab[irq].devname = NULL; */
+	} else { /* == Q40_IRQ_TIMER */
+	  sys_free_irq(4,dev_id);
+	  sys_free_irq(6,dev_id);
+	}
+}
+
+#if 1
+void q40_process_int (int level, struct pt_regs *fp)
+{
+  printk("unexpected interrupt %x\n",level);
+}
+#endif
+
+/* 
+ * tables to translate bits into IRQ numbers 
+ * it is a good idea to order the entries by priority
+ * 
+*/
+
+struct IRQ_TABLE{ unsigned mask; int irq ;};
+
+static struct IRQ_TABLE iirqs[]={
+  {IRQ_FRAME_MASK,Q40_IRQ_FRAME},
+  {IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+  {0,0}};
+static struct IRQ_TABLE eirqs[]={
+  {IRQ3_MASK,3},                   /* ser 1 */
+  {IRQ4_MASK,4},                   /* ser 2 */
+  {IRQ14_MASK,14},                 /* IDE 1 */
+  {IRQ15_MASK,15},                 /* IDE 2 */
+  {IRQ6_MASK,6},                   /* floppy */
+  {IRQ7_MASK,7},                   /* par */
+
+  {IRQ5_MASK,5},
+  {IRQ10_MASK,10},
+
+
+
+
+  {0,0}};
+
+/* complaiun only this many times about spurious ints : */
+static int ccleirq=60;    /* ISA dev IRQ's*/
+static int cclirq=60;     /* internal */
+
+/* FIX: add IRQ_INPROGRESS,mask,unmask,probing.... */
+
+void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+{
+  /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */
+
+        unsigned mir=master_inb(IIRQ_REG);
+	unsigned mer;
+	int irq,i;
+
+	/*
+	 *  more than 1 bit might be set, must handle atmost 1 int source,
+	 *  - handle only those with explicitly set handler
+	 */
+
+	if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK)) 
+	  {
+	    
+	    /* some ISA dev caused the int */
+	    
+	    mer=master_inb(EIRQ_REG);
+	    
+	    for (i=0; eirqs[i].mask; i++)
+	      {
+		if (mer&(eirqs[i].mask)) 
+		  {
+		    irq=eirqs[i].irq;
+		    irq_tab[irq].count++;
+		    if (irq_tab[irq].handler == q40_defhand )
+		      continue; /* ignore uninited INTs :-( */
+		    
+		    irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+		    return;
+		  }
+	      }
+	    if (ccleirq>0) 
+	      printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
+	  } 
+	else 
+	  {
+	    /* internal */
+
+	    for (i=0; iirqs[i].mask; i++)
+	      {
+		if (mir&(iirqs[i].mask)) 
+		  {
+		    irq=iirqs[i].irq;
+		    irq_tab[irq].count++;
+		    if (irq_tab[irq].handler == q40_defhand )
+		      continue; /* ignore uninited INTs :-( */
+		    
+		    irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+		    return;
+		  }
+	      }
+	    if (cclirq>0)
+	      printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--;
+	  }
+}
+
+int q40_get_irq_list (char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i <= Q40_IRQ_MAX; i++) {
+		if (irq_tab[i].count)
+			len += sprintf (buf+len, "Vec 0x%02x: %8d  %s%s\n",
+			    i, irq_tab[i].count,
+			    irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
+			    irq_tab[i].handler == q40_defhand ? 
+					" (now unassigned)" : "");
+	}
+	return len;
+}
+
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if 0
+	printk ("Unknown q40 interrupt 0x%02x\n", irq);
+#endif
+}
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
+{
+#if 0
+        if (ints_inited)
+#endif
+	  printk ("Uninitialised interrupt level %d\n", lev);
+#if 0
+	else
+	  printk ("Interrupt before interrupt initialisation\n");
+#endif
+}
+
+ void (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = {
+   sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler,
+   sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
+ };
+
+void q40_enable_irq (unsigned int irq)
+{
+}
+
+
+void q40_disable_irq (unsigned int irq)
+{
+}
+
+unsigned long q40_probe_irq_on (void)
+{
+  printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n");
+  return 0;
+}
+int q40_probe_irq_off (unsigned long irqs)
+{
+  return -1;
+}
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/sun3x/Makefile linux/arch/m68k/sun3x/Makefile
--- v2.2.7/linux/arch/m68k/sun3x/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/Makefile	Tue May 11 09:57:14 1999
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/sun3x source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := sun3x.o
+O_OBJS   := config.o time.o dvma.o sbus.o
+OX_OBJS  := 
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/sun3x/config.c linux/arch/m68k/sun3x/config.c
--- v2.2.7/linux/arch/m68k/sun3x/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/config.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,128 @@
+/*
+ * Setup kernel for a Sun3x machine
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbo...@alpha.franken.de)
+ *
+ * based on code from Oliver Jowett <oli...@jowett.manawatu.gen.nz>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+static volatile unsigned char *sun3x_intreg = (unsigned char *)SUN3X_INTREG;
+extern int serial_console;
+
+void sun3x_halt(void)
+{
+    /* Disable interrupts */
+    cli();
+
+    /* we can't drop back to PROM, so we loop here */
+    for (;;);
+}
+
+void sun3x_reboot(void)
+{
+    /* This never returns, don't bother saving things */
+    cli();
+
+    /* no idea, whether this works */
+    asm ("reset");
+}
+
+__initfunc(int sun3x_keyb_init(void))
+{
+    return 0;
+}
+
+int sun3x_kbdrate(struct kbd_repeat *r)
+{
+    return 0;
+}
+
+void sun3x_kbd_leds(unsigned int i)
+{
+
+}
+
+static void sun3x_badint (int irq, void *dev_id, struct pt_regs *fp)
+{
+    printk ("received spurious interrupt %d\n",irq);
+    num_spurious += 1;
+}
+
+void (*sun3x_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint,
+    sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint
+};
+
+void sun3x_enable_irq(unsigned int irq)
+{
+    *sun3x_intreg |= (1 << irq);
+}
+
+void sun3x_disable_irq(unsigned int irq)
+{
+    *sun3x_intreg &= ~(1 << irq);
+}
+
+__initfunc(void sun3x_init_IRQ(void))
+{
+    /* disable all interrupts initially */
+    *sun3x_intreg = 1;  /* master enable only */
+}
+
+int sun3x_get_irq_list(char *buf)
+{
+    return 0;
+}
+
+/*
+ *  Setup the sun3x configuration info
+ */
+__initfunc(void config_sun3x(void))
+{
+    mach_get_irq_list	 = sun3x_get_irq_list;
+    mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
+
+    mach_keyb_init       = sun3x_keyb_init;
+    mach_kbdrate         = sun3x_kbdrate;
+    mach_kbd_leds        = sun3x_kbd_leds;
+
+    mach_sched_init      = sun3x_sched_init;
+    mach_init_IRQ        = sun3x_init_IRQ;
+    enable_irq           = sun3x_enable_irq;
+    disable_irq          = sun3x_disable_irq;
+    mach_request_irq     = sys_request_irq;
+    mach_free_irq        = sys_free_irq;
+    mach_default_handler = &sun3x_default_handler;
+    mach_gettimeoffset   = sun3x_gettimeoffset;
+    mach_reset           = sun3x_reboot;
+
+    mach_gettod          = sun3x_gettod;
+    
+    switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
+	case 0x10:
+	    serial_console = 1;
+	    conswitchp = NULL;
+	    break;
+	case 0x11:
+	    serial_console = 2;
+	    conswitchp = NULL;
+	    break;
+	default:
+	    serial_console = 0;
+	    conswitchp = &dummy_con;
+	    break;
+    }
+
+}
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/sun3x/dvma.c linux/arch/m68k/sun3x/dvma.c
--- v2.2.7/linux/arch/m68k/sun3x/dvma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/dvma.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,162 @@
+/*
+ * Virtual DMA allocation
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbo...@alpha.franken.de) 
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+
+#include <asm/sun3x.h>
+#include <asm/dvma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+/* IOMMU support */
+
+#define IOMMU_ENTRIES		   2048
+#define IOMMU_ADDR_MASK            0x03ffe000
+#define IOMMU_CACHE_INHIBIT        0x00000040
+#define IOMMU_FULL_BLOCK           0x00000020
+#define IOMMU_MODIFIED             0x00000010
+#define IOMMU_USED                 0x00000008
+#define IOMMU_WRITE_PROTECT        0x00000004
+#define IOMMU_DT_MASK              0x00000003
+#define IOMMU_DT_INVALID           0x00000000
+#define IOMMU_DT_VALID             0x00000001
+#define IOMMU_DT_BAD               0x00000002
+
+#define DVMA_PAGE_SHIFT	13
+#define DVMA_PAGE_SIZE	(1UL << DVMA_PAGE_SHIFT)
+#define DVMA_PAGE_MASK	(~(DVMA_PAGE_SIZE-1))
+
+
+static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
+static unsigned long iommu_use[IOMMU_ENTRIES];
+static unsigned long iommu_bitmap[IOMMU_ENTRIES/32];
+
+
+#define dvma_entry_paddr(index) 	(iommu_pte[index] & IOMMU_ADDR_MASK)
+#define dvma_entry_vaddr(index,paddr) 	((index << DVMA_PAGE_SHIFT) |  \
+					 (paddr & (DVMA_PAGE_SIZE-1)))
+#define dvma_entry_set(index,addr)	(iommu_pte[index] =            \
+					    (addr & IOMMU_ADDR_MASK) | \
+				             IOMMU_DT_VALID)
+#define dvma_entry_clr(index)		(iommu_pte[index] = IOMMU_DT_INVALID)
+#define dvma_entry_use(index)		(iommu_use[index])
+#define dvma_entry_inc(index)		(iommu_use[index]++)
+#define dvma_entry_dec(index)		(iommu_use[index]--)
+#define dvma_entry_hash(addr)		((addr >> DVMA_PAGE_SHIFT) ^ \
+					 ((addr & 0x03c00000) >>     \
+						(DVMA_PAGE_SHIFT+4)))
+#define dvma_map			iommu_bitmap
+#define dvma_map_size			(IOMMU_ENTRIES/2)
+#define dvma_slow_offset		(IOMMU_ENTRIES/2)
+#define dvma_is_slow(addr)		((addr) & 		      \
+					 (dvma_slow_offset << DVMA_PAGE_SHIFT))
+
+static int fixed_dvma;
+
+void __init dvma_init(void)
+{
+    unsigned long tmp;
+
+    if ((unsigned long)high_memory < (IOMMU_ENTRIES << DVMA_PAGE_SHIFT)) {
+	printk ("Sun3x fixed DVMA mapping\n");
+	fixed_dvma = 1;
+	for (tmp = 0; tmp < (unsigned long)high_memory; tmp += DVMA_PAGE_SIZE)
+	dvma_entry_set (tmp >> DVMA_PAGE_SHIFT, virt_to_phys((void *)tmp));
+	fixed_dvma = 1;
+    } else {
+	printk ("Sun3x variable DVMA mapping\n");
+	for (tmp = 0; tmp < IOMMU_ENTRIES; tmp++)
+	    dvma_entry_clr (tmp);
+	fixed_dvma = 0;
+    }
+}
+
+unsigned long dvma_slow_alloc (unsigned long paddr, int npages)
+{
+    int scan, base;
+    
+    scan = 0;
+    for (;;) {
+	scan = find_next_zero_bit(dvma_map, dvma_map_size, scan);
+	if ((base = scan) + npages > dvma_map_size) {
+	    printk ("dvma_slow_alloc failed for %d pages\n",npages);
+	    return 0;
+	}
+	for  (;;) {
+	    if (scan >= base + npages) goto found;
+	    if (test_bit(scan, dvma_map)) break;
+	    scan++;
+	}
+    }
+
+found:
+    for (scan = base; scan < base+npages; scan++) {
+	dvma_entry_set(scan+dvma_slow_offset, paddr);
+	paddr += DVMA_PAGE_SIZE;
+	set_bit(scan, dvma_map);
+    }
+    return (dvma_entry_vaddr((base+dvma_slow_offset),paddr));
+}
+
+unsigned long dvma_alloc (unsigned long paddr, unsigned long size)
+{
+    int index;
+    int pages = ((paddr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+		DVMA_PAGE_SHIFT;
+
+    if (fixed_dvma)
+	return ((unsigned long)phys_to_virt (paddr));
+
+    if (pages > 1) /* multi page, allocate from slow pool */
+	return dvma_slow_alloc (paddr, pages);
+    
+    index = dvma_entry_hash (paddr);
+
+    if (dvma_entry_use(index)) {
+	if (dvma_entry_paddr(index) == (paddr & DVMA_PAGE_MASK)) {
+	    dvma_entry_inc(index);
+	    return dvma_entry_vaddr(index,paddr);
+	}
+	/* collision, allocate from slow pool */
+	return dvma_slow_alloc (paddr, pages);
+    }
+    
+    dvma_entry_set(index,paddr); 
+    dvma_entry_inc(index);
+    return dvma_entry_vaddr(index,paddr);
+}
+
+void dvma_free (unsigned long dvma_addr, unsigned long size)
+{
+    int npages;
+    int index;
+    
+    if (fixed_dvma)
+	return;
+
+    if (!dvma_is_slow(dvma_addr)) {
+	index = (dvma_addr >> DVMA_PAGE_SHIFT);
+	if (dvma_entry_use(index) == 0) {
+	    printk ("dvma_free: %lx entry already free\n",dvma_addr);
+	    return;
+	}
+        dvma_entry_dec(index);
+	if (dvma_entry_use(index) == 0)
+	    dvma_entry_clr(index);
+	return;
+    }
+
+    /* free in slow pool */
+    npages = ((dvma_addr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+	    DVMA_PAGE_SHIFT;
+    for (index = (dvma_addr >> DVMA_PAGE_SHIFT); npages--; index++) {
+	dvma_entry_clr(index);
+	clear_bit (index,dvma_map);
+    }
+}
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/sun3x/sbus.c linux/arch/m68k/sun3x/sbus.c
--- v2.2.7/linux/arch/m68k/sun3x/sbus.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/sbus.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,44 @@
+/*
+ * SBus helper functions
+ *
+ * Sun3x don't have a sbus, but many of the used devices are also
+ * used on Sparc machines with sbus. To avoid having a lot of
+ * duplicate code, we provide necessary glue stuff to make using
+ * of the sbus driver code possible.
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbo...@alpha.franken.de)
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+__initfunc(void sbus_init(void))
+{
+
+}
+
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+                      u32 bus_type, int rdonly)
+{
+	return (void *)address;
+}
+
+int prom_getintdefault(int node, char *property, int deflt)
+{
+	return deflt;
+}
+
+int prom_getbool (int node, char *prop)
+{
+	return 1;
+}
+
+void prom_printf(char *fmt, ...)
+{
+
+}
+
+void prom_halt (void)
+{
+
+}
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/sun3x/time.c linux/arch/m68k/sun3x/time.c
--- v2.2.7/linux/arch/m68k/sun3x/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/time.c	Tue May 11 09:57:14 1999
@@ -0,0 +1,83 @@
+/*
+ *  linux/arch/m68k/sun3x/time.c
+ *
+ *  Sun3x-specific time handling
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+#define M_CONTROL 0xf8
+#define M_SEC     0xf9
+#define M_MIN     0xfa
+#define M_HOUR    0xfb
+#define M_DAY     0xfc
+#define M_DATE    0xfd
+#define M_MONTH   0xfe
+#define M_YEAR    0xff
+
+#define C_WRITE   0x80
+#define C_READ    0x40
+#define C_SIGN    0x20
+#define C_CALIB   0x1f
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+
+/* Read the Mostek */
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp)
+{
+    volatile unsigned char *eeprom = (unsigned char *)SUN3X_EEPROM;
+
+    /* Stop updates */
+    *(eeprom + M_CONTROL) |= C_READ;
+
+    /* Read values */
+    *yearp = BCD_TO_BIN(*(eeprom + M_YEAR));
+    *monp  = BCD_TO_BIN(*(eeprom + M_MONTH));
+    *dayp  = BCD_TO_BIN(*(eeprom + M_DATE));
+    *hourp = BCD_TO_BIN(*(eeprom + M_HOUR));
+    *minp  = BCD_TO_BIN(*(eeprom + M_MIN));
+    *secp  = BCD_TO_BIN(*(eeprom + M_SEC));
+
+    /* Restart updates */
+    *(eeprom + M_CONTROL) &= ~C_READ;
+}
+
+/* Not much we can do here */
+unsigned long sun3x_gettimeoffset (void)
+{
+    return 0L;
+}
+
+static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+    void (*vector)(int, void *, struct pt_regs *) = dev_id;
+
+    /* Clear the pending interrupt - pulse the enable line low */
+    disable_irq(5);
+    enable_irq(5);
+    
+    vector(irq, NULL, regs);
+}
+
+__initfunc(void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+    sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector);
+
+    /* Pulse enable low to get the clock started */
+    disable_irq(5);
+    enable_irq(5);
+}
diff -u --recursive --new-file v2.2.7/linux/arch/m68k/sun3x/time.h linux/arch/m68k/sun3x/time.h
--- v2.2.7/linux/arch/m68k/sun3x/time.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3x/time.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,9 @@
+#ifndef SUN3X_TIME_H
+#define SUN3X_TIME_H
+
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp);
+unsigned long sun3x_gettimeoffset (void);
+void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *));
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c
--- v2.2.7/linux/arch/mips/kernel/irixioctl.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/mips/kernel/irixioctl.c	Sat May  8 11:14:01 1999
@@ -33,13 +33,15 @@
X {
X 	struct file *filp;
X 
-	if(fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+	file = fcheck(fd);
+	if(!file)
X 		return ((struct tty_struct *) 0);
X 	if(filp->private_data) {
X 		struct tty_struct *ttyp = (struct tty_struct *) filp->private_data;
X 
-		if(ttyp->magic == TTY_MAGIC)
+		if(ttyp->magic == TTY_MAGIC) {
X 			return ttyp;
+		}
X 	}
X 	return ((struct tty_struct *) 0);
X }
diff -u --recursive --new-file v2.2.7/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.2.7/linux/arch/mips/kernel/sysirix.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/mips/kernel/sysirix.c	Sat May  8 11:14:01 1999
@@ -23,6 +23,7 @@
X #include <linux/smp.h>
X #include <linux/smp_lock.h>
X #include <linux/utsname.h>
+#include <linux/file.h>
X 
X #include <asm/ptrace.h>
X #include <asm/page.h>
@@ -734,6 +735,7 @@
X 	int error, i;
X 
X 	/* We don't support this feature yet. */
+	lock_kernel();
X 	if(fs_type) {
X 		error = -EINVAL;
X 		goto out;
@@ -776,7 +778,6 @@
X 
X asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
X {
-	struct dentry *dentry;
X 	struct inode *inode;
X 	struct statfs kbuf;
X 	mm_segment_t old_fs;
@@ -787,25 +788,22 @@
X 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
X 	if (error)
X 		goto out;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+	if (!(file = fget(fd))) {
X 		error = -EBADF;
X 		goto out;
X 	}
-	if (!(dentry = file->f_dentry)) {
+
+	if (!(inode = file->f_dentry->d_inode)) {
X 		error = -ENOENT;
-		goto out;
-	}
-	if (!(inode = dentry->d_inode)) {
-		error = -ENOENT;
-		goto out;
+		goto out_f;
X 	}
X 	if (!inode->i_sb) {
X 		error = -ENODEV;
-		goto out;
+		goto out_f;
X 	}
X 	if (!inode->i_sb->s_op->statfs) {
X 		error = -ENOSYS;
-		goto out;
+		goto out_f;
X 	}
X 
X 	old_fs = get_fs(); set_fs(get_ds());
@@ -813,7 +811,7 @@
X 	                                  sizeof(struct statfs));
X 	set_fs(old_fs);
X 	if (error)
-		goto out;
+		goto out_f;
X 
X 	__put_user(kbuf.f_type, &buf->f_type);
X 	__put_user(kbuf.f_bsize, &buf->f_bsize);
@@ -826,9 +824,9 @@
X 		__put_user(0, &buf->f_fname[i]);
X 		__put_user(0, &buf->f_fpack[i]);
X 	}
-	error = 0;
X 
-	dput(dentry);
+out_f:
+	fput(file);
X out:
X 	unlock_kernel();
X 	return error;
@@ -1110,7 +1108,7 @@
X 
X 	lock_kernel();
X 	if(!(flags & MAP_ANONYMOUS)) {
-		if(fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+		if(!(file = fget(fd))) {
X 			retval = -EBADF;
X 			goto out;
X 		}
@@ -1130,6 +1128,8 @@
X 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
X 
X 	retval = do_mmap(file, addr, len, prot, flags, offset);
+	if (file)
+		fput(file);
X 
X out:
X 	unlock_kernel();
@@ -1568,7 +1568,6 @@
X 
X asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
X {
-	struct dentry *dentry;
X 	struct inode *inode;
X 	mm_segment_t old_fs;
X 	struct statfs kbuf;
@@ -1582,21 +1581,21 @@
X 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
X 	if (error)
X 		goto out;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+	if (!(file = fget(fd))) {
X 		error = -EBADF;
X 		goto out;
X 	}
-	if (!(dentry = file->f_dentry)) {
+	if (!(inode = file->f_dentry->d_inode)) {
X 		error = -ENOENT;
-		goto out;
+		goto out_f;
X 	}
-	if (!(inode = dentry->d_inode)) {
-		error = -ENOENT;
-		goto out;
+	if (!inode->i_sb) {
+		error = -ENODEV;
+		goto out_f;
X 	}
X 	if (!inode->i_sb->s_op->statfs) {
X 		error = -ENOSYS;
-		goto out;
+		goto out_f;
X 	}
X 
X 	old_fs = get_fs(); set_fs(get_ds());
@@ -1604,7 +1603,7 @@
X 	                                  sizeof(struct statfs));
X 	set_fs(old_fs);
X 	if (error)
-		goto out;
+		goto out_f;
X 
X 	__put_user(kbuf.f_bsize, &buf->f_bsize);
X 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1626,9 +1625,8 @@
X 	for(i = 0; i < 32; i++)
X 		__put_user(0, &buf->f_fstr[i]);
X 
-	error = 0;
-
-	dput(dentry);
+out_f:
+	fput(file);
X out:
X 	unlock_kernel();
X 	return error;
@@ -1726,7 +1724,7 @@
X 	}
X 
X 	if(!(flags & MAP_ANONYMOUS)) {
-		if(fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+		if(!(file = fcheck(fd))) {
X 			error = -EBADF;
X 			goto out;
X 		}
@@ -1812,6 +1810,7 @@
X 	struct statfs kbuf;
X 	int error, i;
X 
+	lock_kernel();
X 	printk("[%s:%ld] Wheee.. irix_statvfs(%s,%p)\n",
X 	       current->comm, current->pid, fname, buf);
X 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
@@ -1864,7 +1863,6 @@
X 
X asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
X {
-	struct dentry *dentry;
X 	struct inode *inode;
X 	mm_segment_t old_fs;
X 	struct statfs kbuf;
@@ -1878,21 +1876,21 @@
X 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
X 	if (error)
X 		goto out;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+	if (!(file = fget(fd))) {
X 		error = -EBADF;
X 		goto out;
X 	}
-	if (!(dentry = file->f_dentry)) {
+	if (!(inode = file->f_dentry->d_inode)) {
X 		error = -ENOENT;
-		goto out;
+		goto out_f;
X 	}
-	if (!(inode = dentry->d_inode)) {
-		error = -ENOENT;
-		goto out;
+	if (!inode->i_sb) {
+		error = -ENODEV;
+		goto out_f;
X 	}
X 	if (!inode->i_sb->s_op->statfs) {
X 		error = -ENOSYS;
-		goto out;
+		goto out_f;
X 	}
X 
X 	old_fs = get_fs(); set_fs(get_ds());
@@ -1900,7 +1898,7 @@
X 	                                  sizeof(struct statfs));
X 	set_fs(old_fs);
X 	if (error)
-		goto out;
+		goto out_f;
X 
X 	__put_user(kbuf.f_bsize, &buf->f_bsize);
X 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1921,10 +1919,8 @@
X 	__put_user(kbuf.f_namelen, &buf->f_namemax);
X 	for(i = 0; i < 32; i++)
X 		__put_user(0, &buf->f_fstr[i]);
-
-	error = 0;
-
-	dput(dentry);
+out_f:
+	fput(file);
X out:
X 	unlock_kernel();
X 	return error;
@@ -1994,7 +1990,6 @@
X 	unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
X 	int retval;
X 
-	lock_kernel();
X #ifdef DEBUG_GETDENTS
X 	printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
X 	       reclen, namlen, buf->count);
@@ -2020,14 +2015,12 @@
X 	retval = 0;
X 
X out:
-	unlock_kernel();
X 	return retval;
X }
X 
X asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
X {
X 	struct file *file;
-	struct dentry *dentry;
X 	struct inode *inode;
X 	struct irix_dirent32 *lastdirent;
X 	struct irix_dirent32_callback buf;
@@ -2039,46 +2032,56 @@
X 	       current->pid, fd, dirent, count, eob);
X #endif
X 	error = -EBADF;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	file = fget(fd);
+	if (!file)
X 		goto out;
X 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out;
+	inode = file->f_dentry->d_inode;
+	if (!inode)
+		goto out_putf;
X 
X 	inode = dentry->d_inode;
X 	if (!inode)
-		goto out;
+		goto out_putf;
X 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out;
-
-	error = -EFAULT;
-	if(!access_ok(VERIFY_WRITE, dirent, count) ||
-	   !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
-		goto out;
-
-	__put_user(0, eob);
X 	buf.current_dir = (struct irix_dirent32 *) dirent;
X 	buf.previous = NULL;
X 	buf.count = count;
X 	buf.error = 0;
X 
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out_putf;
+
+	/*
+	 * Get the inode's semaphore to prevent changes
+	 * to the directory while we read it.
+	 */
+	down(&inode->i_sem);
X 	error = file->f_op->readdir(file, &buf, irix_filldir32);
+	up(&inode->i_sem);
X 	if (error < 0)
-		goto out;
+		goto out_putf;
+	error = buf.error;
X 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-		goto out;
+	if (lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
X 	}
-	lastdirent->d_off = (u32) file->f_pos;
+
+	if (put_user(0, eob) < 0) {
+		error = EFAULT;
+		goto out_putf;
+	}
+
+
X #ifdef DEBUG_GETDENTS
X 	printk("eob=%d returning %d\n", *eob, count - buf.count);
X #endif
X 	error = count - buf.count;
X 
+out_putf:
+	fput(file);
X out:
X 	unlock_kernel();
X 	return error;
@@ -2110,7 +2113,6 @@
X 	unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1);
X 	int retval;
X 
-	lock_kernel();
X 	buf->error = -EINVAL;	/* only used if we fail.. */
X 	if (reclen > buf->count) {
X 		retval = -EINVAL;
@@ -2131,14 +2133,12 @@
X 
X 	retval = 0;
X out:
-	unlock_kernel();
X 	return retval;
X }
X 
X asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
X {
X 	struct file *file;
-	struct dentry *dentry;
X 	struct inode *inode;
X 	struct irix_dirent64 *lastdirent;
X 	struct irix_dirent64_callback buf;
@@ -2150,40 +2150,38 @@
X 	       current->pid, fd, dirent, cnt);
X #endif
X 	error = -EBADF;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		goto out;
-
-	dentry = file->f_dentry;
-	if (!dentry)
+	if (!(file = fget(fd)))
X 		goto out;
X 
-	inode = dentry->d_inode;
+	inode = file->f_dentry->d_inode;
X 	if (!inode)
-		goto out;
+		goto out_f;
X 
X 	error = -ENOTDIR;
X 	if (!file->f_op || !file->f_op->readdir)
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 07'
echo 'File patch-2.2.8 is continued in part 08'
echo 08 > _shar_seq_.tmp
#!/bin/sh
# this is part 08 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 08; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
-		goto out;
+		goto out_f;
X 
X 	error = -EFAULT;
X 	if(!access_ok(VERIFY_WRITE, dirent, cnt))
-		goto out;
+		goto out_f;
X 
X 	error = -EINVAL;
X 	if(cnt < (sizeof(struct irix_dirent64) + 255))
-		goto out;
+		goto out_f;
X 
X 	buf.curr = (struct irix_dirent64 *) dirent;
X 	buf.previous = NULL;
X 	buf.count = cnt;
X 	buf.error = 0;
+	down(&inode->i_sem);
X 	error = file->f_op->readdir(file, &buf, irix_filldir64);
+	up(&inode->i_sem);
X 	if (error < 0)
-		goto out;
+		goto out_f;
X 	lastdirent = buf.previous;
X 	if (!lastdirent) {
X 		error = buf.error;
-		goto out;
+		goto out_f;
X 	}
X 	lastdirent->d_off = (u64) file->f_pos;
X #ifdef DEBUG_GETDENTS
@@ -2191,6 +2189,8 @@
X #endif
X 	error = cnt - buf.count;
X 
+out_f:
+	fput(file);
X out:
X 	unlock_kernel();
X 	return error;
@@ -2199,7 +2199,6 @@
X asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
X {
X 	struct file *file;
-	struct dentry *dentry;
X 	struct inode *inode;
X 	struct irix_dirent64 *lastdirent;
X 	struct irix_dirent64_callback buf;
@@ -2211,42 +2210,40 @@
X 	       current->pid, fd, dirent, cnt);
X #endif
X 	error = -EBADF;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		goto out;
-
-	dentry = file->f_dentry;
-	if (!dentry)
+	if (!(file = fget(fd)))
X 		goto out;
X 
-	inode = dentry->d_inode;
+	inode = file->f_dentry->d_inode;
X 	if (!inode)
-		goto out;
+		goto out_f;
X 
X 	error = -ENOTDIR;
X 	if (!file->f_op || !file->f_op->readdir)
-		goto out;
+		goto out_f;
X 
X 	error = -EFAULT;
X 	if(!access_ok(VERIFY_WRITE, dirent, cnt) ||
X 	   !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
-		goto out;
+		goto out_f;
X 
X 	error = -EINVAL;
X 	if(cnt < (sizeof(struct irix_dirent64) + 255))
-		goto out;
+		goto out_f;
X 
X 	*eob = 0;
X 	buf.curr = (struct irix_dirent64 *) dirent;
X 	buf.previous = NULL;
X 	buf.count = cnt;
X 	buf.error = 0;
+	down(&inode->i_sem);
X 	error = file->f_op->readdir(file, &buf, irix_filldir64);
+	up(&inode->i_sem);
X 	if (error < 0)
-		goto out;
+		goto out_f;
X 	lastdirent = buf.previous;
X 	if (!lastdirent) {
X 		error = buf.error;
-		goto out;
+		goto out_f;
X 	}
X 	lastdirent->d_off = (u64) file->f_pos;
X #ifdef DEBUG_GETDENTS
@@ -2254,6 +2251,8 @@
X #endif
X 	error = cnt - buf.count;
X 
+out_f:
+	fput(file);
X out:
X 	unlock_kernel();
X 	return error;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.2.7/linux/arch/ppc/boot/Makefile	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/boot/Makefile	Thu Apr 29 12:39:01 1999
@@ -14,7 +14,7 @@
X .s.o:
X 	$(AS) -o $*.o $<
X .c.o:
-	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
+	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
X .S.s:
X 	$(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
X .S.o:
@@ -57,7 +57,7 @@
X 		-DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \
X 		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \
X 		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \
-		-DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+		-c -o misc.o misc.c
X 	$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
X 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
X 		--add-section=initrd=ramdisk.image.gz \
@@ -84,7 +84,7 @@
X #
X 	$(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
X 		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \
-		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \
X 		-c -o misc.o misc.c
X 	$(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
X 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
@@ -95,7 +95,7 @@
X 	dd if=zImage of=/dev/fd0H1440 bs=64b
X 
X mkprep : mkprep.c
-	$(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
+	$(HOSTCC) -o mkprep mkprep.c
X 
X znetboot : zImage
X 	cp zImage $(TFTPIMAGE)
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S
--- v2.2.7/linux/arch/ppc/boot/head.S	Fri Apr 16 14:47:30 1999
+++ linux/arch/ppc/boot/head.S	Thu Apr 29 12:39:01 1999
@@ -6,7 +6,7 @@
X 	.text
X 
X /*
- * $Id: head.S,v 1.29 1999/03/08 23:41:17 cort Exp $
+ * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $
X  *	
X  * Boot loader philosophy:
X  *      ROM loads us to some arbitrary location
@@ -23,11 +23,7 @@
X start_:
X 	mr	r11,r3		/* Save pointer to residual/board data */
X 	mr      r25,r5          /* Save OFW pointer */
-
-	mfmsr	r3		/* Turn off interrupts  */
-	li	r4,0
-	ori	r4,r4,MSR_EE
-	andc	r3,r3,r4
+	li	r3,MSR_IP	/* Establish default MSR value */
X 	mtmsr	r3
X 
X /* check if we need to relocate ourselves to the link addr or were we
@@ -136,6 +132,20 @@
X 	lis	r10,0xdeadc0de@h
X 	ori	r10,r10,0xdeadc0de@l
X 	stw	r10,0(r9)
+/*
+ * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
+ * so disable BATs before setting this to avoid a clash
+ */
+	li      r8,0
+	mtspr   DBAT0U,r8
+	mtspr   DBAT1U,r8
+	mtspr   DBAT2U,r8
+	mtspr   DBAT3U,r8
+	mtspr   IBAT0U,r8
+	mtspr   IBAT1U,r8
+	mtspr   IBAT2U,r8
+	mtspr   IBAT3U,r8
+
X 	blr
X hang:
X 	b	hang	
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/kbd.c linux/arch/ppc/boot/kbd.c
--- v2.2.7/linux/arch/ppc/boot/kbd.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/boot/kbd.c	Thu Apr 29 12:39:01 1999
@@ -127,6 +127,11 @@
X 	unsigned char c;
X 	int i;
X 
+	/* flush input queue */
+	while ((inb(KBSTATP) & KBINRDY))
+	{
+		(void)inb(KBDATAP);
+	}
X 	/* Send self-test */
X 	while (inb(KBSTATP) & KBOUTRDY) ;
X 	outb(KBSTATP,0xAA);
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- v2.2.7/linux/arch/ppc/boot/misc.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/boot/misc.c	Tue May 11 08:24:32 1999
@@ -1,7 +1,7 @@
X /*
X  * misc.c
X  *
- * $Id: misc.c,v 1.61 1999/03/08 23:51:02 cort Exp $
+ * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $
X  * 
X  * Adapted for PowerPC by Gary Thomas
X  *
@@ -33,14 +33,16 @@
X char *end_avail;
X extern char _end[];
X 
-#if defined(CONFIG_SERIAL_CONSOLE)
-char cmd_preset[] = "console=ttyS0,9600n8";
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
X #else
-char cmd_preset[] = "";
+#define CMDLINE "";
X #endif
-char	cmd_buf[256];
-char	*cmd_line = cmd_buf;
+char cmd_preset[] = CMDLINE;
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
X 
+int keyb_present = 1;	/* keyboard controller is present by default */
X RESIDUAL hold_resid_buf;
X RESIDUAL *hold_residual = &hold_resid_buf;
X unsigned long initrd_start = 0, initrd_end = 0;
@@ -58,7 +60,8 @@
X void * memcpy(void * __dest, __const void * __src,
X 			    int __n);
X void gunzip(void *, int, unsigned char *, int *);
-int _cvt(unsigned long val, char *buf, long radix, char *digits);
+static int _cvt(unsigned long val, char *buf, long radix, char *digits);
+unsigned char inb(int);
X 
X void pause()
X {
@@ -93,11 +96,14 @@
X 
X tstc(void)
X {
-	return (
X #if defined(CONFIG_SERIAL_CONSOLE)
-		NS16550_tstc(com_port) ||
+	if (keyb_present)
+		return (CRT_tstc() || NS16550_tstc(com_port));
+	else
+		NS16550_tstc(com_port);
+#else
+	return (CRT_tstc() );
X #endif /* CONFIG_SERIAL_CONSOLE */
-		CRT_tstc());
X }
X 
X getc(void)
@@ -106,7 +112,8 @@
X #if defined(CONFIG_SERIAL_CONSOLE)
X 		if (NS16550_tstc(com_port)) return (NS16550_getc(com_port));
X #endif /* CONFIG_SERIAL_CONSOLE */
-		if (CRT_tstc()) return (CRT_getc());
+		if (keyb_present)
+			if (CRT_tstc()) return (CRT_getc());
X 	}
X }
X 
@@ -188,6 +195,8 @@
X 		}
X 	}
X 
+	cursor(x, y);
+
X 	orig_x = x;
X 	orig_y = y;
X }
@@ -317,6 +326,8 @@
X 	int dev_handle;
X 	int mem_info[2];
X 	int res, size;
+	unsigned char board_type;
+	unsigned char base_mod;
X 
X 	lines = 25;
X 	cols = 80;
@@ -333,14 +344,31 @@
X 	flush_instruction_cache();
X 	_put_HID0(_get_HID0() & ~0x0000C000);
X 	_put_MSR((orig_MSR = _get_MSR()) & ~0x0030);
-	vga_init(0xC0000000);
X 
X #if defined(CONFIG_SERIAL_CONSOLE)
-	com_port = (struct NS16550 *)NS16550_init(1);
+	com_port = (struct NS16550 *)NS16550_init(0);
X #endif /* CONFIG_SERIAL_CONSOLE */
+	vga_init(0xC0000000);
X 
X 	if (residual)
X 	{
+		/* Is this Motorola PPCBug? */
+		if ((1 & residual->VitalProductData.FirmwareSupports) &&
+		    (1 == residual->VitalProductData.FirmwareSupplier)) {
+			board_type = inb(0x800) & 0xF0;
+
+			/* If this is genesis 2 board then check for no
+			 * keyboard controller and more than one processor.
+			 */
+			if (board_type == 0xe0) {	
+				base_mod = inb(0x803);
+				/* if a MVME2300/2400 or a Sitka then no keyboard */
+				if((base_mod == 0x9) || (base_mod == 0xF9) ||
+				   (base_mod == 0xE1)) {
+					keyb_present = 0;	/* no keyboard */
+				}
+			}
+		}
X 		memcpy(hold_residual,residual,sizeof(RESIDUAL));
X 	} else {
X 		/* Assume 32M in the absence of more info... */
@@ -429,7 +457,7 @@
X 	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
X 	puts("zimage at:     "); puthex((unsigned long)zimage_start);
X 	puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
-	if ( (unsigned long)zimage_start <= 0x008000000 )
+	if ( (unsigned long)zimage_start <= 0x00800000 )
X 	{
X 		memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
X 		zimage_start = (char *)avail_ram;
@@ -444,6 +472,7 @@
X 	{
X 		puts("initrd at:     "); puthex(initrd_start);
X 		puts(" "); puthex(initrd_end); puts("\n");
+#ifdef OMIT
X 		avail_ram = (char *)PAGE_ALIGN(
X 			(unsigned long)zimage_size+(unsigned long)zimage_start);
X 		memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
@@ -451,6 +480,7 @@
X 		initrd_end = initrd_start + INITRD_SIZE;
X 		puts("relocated to:  "); puthex(initrd_start);
X 		puts(" "); puthex(initrd_end); puts("\n");
+#endif
X 	}
X 
X 	avail_ram = (char *)0x00400000;
@@ -458,9 +488,8 @@
X 	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
X 	puthex((unsigned long)end_avail); puts("\n");
X 
-#if !defined(CONFIG_SERIAL_CONSOLE)
-	CRT_tstc();  /* Forces keyboard to be initialized */
-#endif
+	if (keyb_present)
+		CRT_tstc();  /* Forces keyboard to be initialized */
X 
X 	puts("\nLinux/PPC load: ");
X 	timer = 0;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c
--- v2.2.7/linux/arch/ppc/boot/mkprep.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/boot/mkprep.c	Thu Apr 29 12:39:01 1999
@@ -14,15 +14,8 @@
X  * Modified for x86 hosted builds by Matt Porter <por...@neta.com>
X  */
X 
-#ifdef linux
-#include <linux/types.h>
-/*#include <asm/stat.h>*/
-/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
-#else
X #include <unistd.h>
-#endif
X #include <sys/stat.h>
-
X #include <stdio.h>
X #include <errno.h>
X 
@@ -168,10 +161,10 @@
X   /* set entry point and boot image size skipping over elf header */
X #ifdef __i386__
X   *entry = 0x400/*+65536*/;
-  *length = info.st_size+0x400;
+  *length = info.st_size-elfhdr_size+0x400;
X #else
X   *entry = cpu_to_le32(0x400/*+65536*/);
-  *length = cpu_to_le32(info.st_size+0x400);
+  *length = cpu_to_le32(info.st_size-elfhdr_size+0x400);
X #endif /* __i386__ */
X 
X   /* sets magic number for msdos partition (used by linux) */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.2.7/linux/arch/ppc/common_defconfig	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/common_defconfig	Tue May 11 08:24:32 1999
@@ -1,5 +1,5 @@
X #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
X #
X 
X #
@@ -42,13 +42,13 @@
X CONFIG_MAC_KEYBOARD=y
X CONFIG_MAC_FLOPPY=y
X CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
X CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
X CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
X # CONFIG_TOTALMP is not set
X CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
X 
X #
X # Plug and Play support
@@ -60,6 +60,10 @@
X #
X # CONFIG_BLK_DEV_FD is not set
X CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
X # CONFIG_BLK_DEV_HD_IDE is not set
X CONFIG_BLK_DEV_IDEDISK=y
X CONFIG_BLK_DEV_IDECD=y
@@ -70,8 +74,14 @@
X # CONFIG_BLK_DEV_RZ1000 is not set
X # CONFIG_BLK_DEV_IDEPCI is not set
X # CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
X # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=y
X # CONFIG_BLK_DEV_NBD is not set
X # CONFIG_BLK_DEV_MD is not set
X CONFIG_BLK_DEV_RAM=y
@@ -101,10 +111,17 @@
X # CONFIG_IP_MROUTE is not set
X CONFIG_IP_ALIAS=y
X # CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
X CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
X CONFIG_SKB_LARGE=y
X # CONFIG_IPV6 is not set
+
+#
+#  
+#
X # CONFIG_IPX is not set
X CONFIG_ATALK=m
X # CONFIG_X25 is not set
@@ -126,12 +143,20 @@
X # SCSI support
X #
X CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
X CONFIG_BLK_DEV_SD=y
X CONFIG_CHR_DEV_ST=y
X CONFIG_BLK_DEV_SR=y
X CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
X CONFIG_SCSI_CONSTANTS=y
X # CONFIG_SCSI_LOGGING is not set
X 
@@ -159,10 +184,15 @@
X # CONFIG_SCSI_FUTURE_DOMAIN is not set
X # CONFIG_SCSI_GDTH is not set
X # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
X # CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
X # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
X # CONFIG_SCSI_NCR53C7xx is not set
X CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
X CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
X CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
X CONFIG_SCSI_NCR53C8XX_SYNC=20
@@ -175,6 +205,7 @@
X # CONFIG_SCSI_PSI240I is not set
X # CONFIG_SCSI_QLOGIC_FAS is not set
X # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
X # CONFIG_SCSI_SEAGATE is not set
X # CONFIG_SCSI_DC390T is not set
X # CONFIG_SCSI_T128 is not set
@@ -205,7 +236,7 @@
X # CONFIG_ACENIC is not set
X # CONFIG_NET_ISA is not set
X CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
X # CONFIG_AC3200 is not set
X # CONFIG_APRICOT is not set
X # CONFIG_CS89x0 is not set
@@ -229,6 +260,10 @@
X # CONFIG_COPS is not set
X # CONFIG_IPDDP is not set
X CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
X # CONFIG_SLIP is not set
X # CONFIG_NET_RADIO is not set
X # CONFIG_TR is not set
@@ -256,22 +291,37 @@
X # Console drivers
X #
X CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
X CONFIG_FB_OF=y
X CONFIG_FB_CONTROL=y
X CONFIG_FB_PLATINUM=y
X CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
X CONFIG_FB_IMSTT=y
X CONFIG_FB_CT65550=y
X # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
X # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
X CONFIG_FBCON_CFB8=y
X CONFIG_FBCON_CFB16=y
X CONFIG_FBCON_CFB24=y
X CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
X # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
X CONFIG_FBCON_FONTS=y
X # CONFIG_FONT_8x8 is not set
@@ -287,12 +337,22 @@
X #
X CONFIG_VT=y
X CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
X # CONFIG_SERIAL_EXTENDED is not set
X # CONFIG_SERIAL_NONSTANDARD is not set
X CONFIG_UNIX98_PTYS=y
X CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+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
X # CONFIG_QIC02_TAPE is not set
X # CONFIG_WATCHDOG is not set
X # CONFIG_NVRAM is not set
@@ -307,11 +367,20 @@
X # Joystick support
X #
X # CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
X 
X #
X # Ftape, the floppy tape device driver
X #
X # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
X 
X #
X # Filesystems
@@ -402,3 +471,10 @@
X # CONFIG_SOUND_MSNDCLAS is not set
X # CONFIG_SOUND_MSNDPIN is not set
X # CONFIG_SOUND_OSS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.2.7/linux/arch/ppc/config.in	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/config.in	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.84 1999/02/23 08:08:38 davem Exp $
+# $Id: config.in,v 1.92 1999/04/30 05:41:43 cort Exp $
X # For a description of the syntax of this configuration file,
X # see the Configure script.
X #
@@ -19,12 +19,10 @@
X   	 APUS           CONFIG_APUS \
X 	 MBX		CONFIG_MBX" PowerMac
X 
+bool 'Symmetric multi-processing support' CONFIG_SMP
X if [ "$CONFIG_ALL_PPC" != "y" ];then
X   define_bool CONFIG_MACH_SPECIFIC y
X fi
-
-bool 'Symmetric multi-processing support' CONFIG_SMP
-
X endmenu
X 
X if [ "$CONFIG_MBX" = "y" ];then
@@ -82,13 +80,20 @@
X bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
X bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
X bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
X bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
-bool 'Support for PowerMac IDE devices (must also enable IDE)' CONFIG_BLK_DEV_IDE_PMAC
X bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
-bool 'Include kgdb kernel debugger' CONFIG_KGDB
-bool 'Include xmon kernel debugger' CONFIG_XMON
X bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
X bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
+bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
+if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+  bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y
+  if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
+    string 'Initial kernel command string' CONFIG_CMDLINE console=ttyS0,9600 console=tty0 root=/dev/sda2
+  fi
+fi
X 
X if [ "$CONFIG_APUS" = "y" ]; then
X   define_bool CONFIG_FB_CONSOLE y
@@ -176,4 +181,12 @@
X   source drivers/sound/Config.in
X fi
X 
+endmenu
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Include kgdb kernel debugger' CONFIG_KGDB
+bool 'Include xmon kernel debugger' CONFIG_XMON
X endmenu
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.2.7/linux/arch/ppc/defconfig	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/defconfig	Tue May 11 08:24:32 1999
@@ -8,13 +8,12 @@
X CONFIG_PPC=y
X CONFIG_6xx=y
X # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
X # CONFIG_PREP is not set
X # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
X # CONFIG_APUS is not set
X # CONFIG_MBX is not set
-CONFIG_MACH_SPECIFIC=y
X # CONFIG_SMP is not set
X 
X #
@@ -36,20 +35,20 @@
X CONFIG_BINFMT_MISC=m
X # CONFIG_BINFMT_JAVA is not set
X # CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
X CONFIG_FB=y
X CONFIG_FB_COMPAT_XPMAC=y
X CONFIG_PMAC_PBOOK=y
X CONFIG_MAC_KEYBOARD=y
X CONFIG_MAC_FLOPPY=y
X CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
X CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
X CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
X # CONFIG_TOTALMP is not set
X CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
X 
X #
X # Plug and Play support
@@ -76,15 +75,13 @@
X # CONFIG_BLK_DEV_IDEPCI is not set
X # CONFIG_BLK_DEV_SL82C105 is not set
X CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
X # CONFIG_IDE_CHIPSETS is not set
X 
X #
X # Additional Block Devices
X #
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
X # CONFIG_BLK_DEV_NBD is not set
X # CONFIG_BLK_DEV_MD is not set
X CONFIG_BLK_DEV_RAM=y
@@ -119,7 +116,6 @@
X # (it is safe to leave these untouched)
X #
X CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
X CONFIG_SKB_LARGE=y
X # CONFIG_IPV6 is not set
X 
@@ -155,12 +151,12 @@
X CONFIG_CHR_DEV_ST=y
X CONFIG_BLK_DEV_SR=y
X CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
X 
X #
X # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
X #
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_MULTI_LUN=y
X CONFIG_SCSI_CONSTANTS=y
X # CONFIG_SCSI_LOGGING is not set
X 
@@ -188,16 +184,28 @@
X # CONFIG_SCSI_FUTURE_DOMAIN is not set
X # CONFIG_SCSI_GDTH is not set
X # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
X # CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
X # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
X # CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
X # CONFIG_SCSI_PAS16 is not set
X # CONFIG_SCSI_PCI2000 is not set
X # CONFIG_SCSI_PCI2220I is not set
X # CONFIG_SCSI_PSI240I is not set
X # CONFIG_SCSI_QLOGIC_FAS is not set
X # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
X # CONFIG_SCSI_SEAGATE is not set
X # CONFIG_SCSI_DC390T is not set
X # CONFIG_SCSI_T128 is not set
@@ -228,7 +236,7 @@
X # CONFIG_ACENIC is not set
X # CONFIG_NET_ISA is not set
X CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
X # CONFIG_AC3200 is not set
X # CONFIG_APRICOT is not set
X # CONFIG_CS89x0 is not set
@@ -275,7 +283,7 @@
X # CONFIG_ISDN is not set
X 
X #
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
X #
X # CONFIG_CD_NO_IDESCSI is not set
X 
@@ -283,22 +291,37 @@
X # Console drivers
X #
X CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
X CONFIG_FB_OF=y
X CONFIG_FB_CONTROL=y
X CONFIG_FB_PLATINUM=y
X CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
X CONFIG_FB_IMSTT=y
X CONFIG_FB_CT65550=y
X # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
X # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
X CONFIG_FBCON_CFB8=y
X CONFIG_FBCON_CFB16=y
X CONFIG_FBCON_CFB24=y
X CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
X # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
X CONFIG_FBCON_FONTS=y
X # CONFIG_FONT_8x8 is not set
@@ -314,15 +337,25 @@
X #
X CONFIG_VT=y
X CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
X # CONFIG_SERIAL_EXTENDED is not set
X # CONFIG_SERIAL_NONSTANDARD is not set
X CONFIG_UNIX98_PTYS=y
X CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+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
X # CONFIG_QIC02_TAPE is not set
X # CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
+# CONFIG_NVRAM is not set
X # CONFIG_RTC is not set
X 
X #
@@ -334,11 +367,20 @@
X # Joystick support
X #
X # CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
X 
X #
X # Ftape, the floppy tape device driver
X #
X # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
X 
X #
X # Filesystems
@@ -429,3 +471,10 @@
X # CONFIG_SOUND_MSNDCLAS is not set
X # CONFIG_SOUND_MSNDPIN is not set
X # CONFIG_SOUND_OSS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.2.7/linux/arch/ppc/kernel/Makefile	Mon Dec 28 15:00:52 1998
+++ linux/arch/ppc/kernel/Makefile	Thu Apr 29 12:39:01 1999
@@ -27,7 +27,7 @@
X endif
X 
X ifeq ($(CONFIG_MBX),y)
-O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o
+O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
X else
X ifeq ($(CONFIG_APUS),y)
X O_OBJS += apus_setup.o prom.o openpic.o
@@ -36,7 +36,8 @@
X O_OBJS += prep_time.o pmac_time.o chrp_time.o \
X 	  pmac_setup.o pmac_support.o \
X 	  prep_pci.o pmac_pci.o chrp_pci.o \
-	  residual.o prom.o openpic.o feature.o
+	  residual.o prom.o openpic.o feature.o \
+	  prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o
X OX_OBJS += chrp_setup.o prep_setup.o
X endif
X endif
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/align.c linux/arch/ppc/kernel/align.c
--- v2.2.7/linux/arch/ppc/kernel/align.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/align.c	Thu Apr 29 12:39:01 1999
@@ -194,13 +194,8 @@
X 			return -EFAULT;	/* bad address */
X 	}
X 
-#ifdef __SMP__
-	if ((flags & F) && (regs->msr & MSR_FP) )
-		smp_giveup_fpu(current);
-#else	
-	if ((flags & F) && last_task_used_math == current)
-		giveup_fpu();
-#endif
+	if ((flags & F) && (regs->msr & MSR_FP))
+		giveup_fpu(current);
X 	if (flags & M)
X 		return 0;		/* too hard for now */
X 
@@ -254,27 +249,16 @@
X 		data.d = current->tss.fpr[reg];
X 		break;
X 	/* these require some floating point conversions... */
-	/* note that giveup_fpu enables the FPU for the kernel */
X 	/* we'd like to use the assignment, but we have to compile
X 	 * the kernel with -msoft-float so it doesn't use the
X 	 * fp regs for copying 8-byte objects. */
X 	case LD+F+S:
-#ifdef __SMP__
-		if (regs->msr & MSR_FP )
-			smp_giveup_fpu(current);
-#else	
-		giveup_fpu();
-#endif		
+		enable_kernel_fp();
X 		cvt_fd(&data.f, ¤t->tss.fpr[reg], ¤t->tss.fpscr);
X 		/* current->tss.fpr[reg] = data.f; */
X 		break;
X 	case ST+F+S:
-#ifdef __SMP__
-		if (regs->msr & MSR_FP )
-			smp_giveup_fpu(current);
-#else	
-		giveup_fpu();
-#endif		
+		enable_kernel_fp();
X 		cvt_df(¤t->tss.fpr[reg], &data.f, ¤t->tss.fpscr);
X 		/* data.f = current->tss.fpr[reg]; */
X 		break;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.2.7/linux/arch/ppc/kernel/apus_setup.c	Tue Dec 22 14:16:54 1998
+++ linux/arch/ppc/kernel/apus_setup.c	Thu Apr 29 12:39:01 1999
@@ -14,12 +14,50 @@
X #include <linux/sched.h>
X #include <linux/kd.h>
X #include <linux/init.h>
+#include <linux/hdreg.h>
+
+/* Get the IDE stuff from the 68k file */
+#define ide_init_hwif_ports m68k_ide_init_hwif_ports
+#define ide_default_irq m68k_ide_default_irq
+#define ide_default_io_base m68k_ide_default_io_base
+#define ide_check_region m68k_ide_check_region
+#define ide_request_region m68k_ide_request_region
+#define ide_release_region m68k_ide_release_region
+#define ide_fix_driveid m68k_ide_fix_driveid
+#include <asm-m68k/ide.h>
+#undef ide_init_hwif_ports
+#define ide_default_irq
+#define ide_default_io_base
+#define ide_check_region
+#define ide_request_region
+#define ide_release_region
+#define ide_fix_driveid
+
X 
X #include <asm/setup.h>
X #include <asm/amigahw.h>
X #include <asm/amigappc.h>
X #include <asm/pgtable.h>
X #include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+unsigned long apus_get_rtc_time(void);
+int apus_set_rtc_time(unsigned long nowtime);
+
+/* APUS defs */
+extern int parse_bootinfo(const struct bi_record *);
+extern char _end[];
+#ifdef CONFIG_APUS
+struct mem_info ramdisk;
+unsigned long isa_io_base;
+unsigned long isa_mem_base;
+unsigned long pci_dram_offset;
+#endif
+/* END APUS defs */
X 
X unsigned long m68k_machtype;
X char debug_device[6] = "";
@@ -72,6 +110,8 @@
X 	int i;
X 	char *p, *q;
X 
+	m68k_machtype = MACH_AMIGA;
+
X 	/* Parse the command line for arch-specific options.
X 	 * For the m68k, this is currently only "debug=xxx" to enable printing
X 	 * certain kernel messages to some machine-specific device.  */
@@ -408,4 +448,195 @@
X 	       "icbi 0,%0 \n\t"
X 	       "isync \n\t"
X 	       : : "r" (addr));
+}
+
+void
+apus_restart(char *cmd)
+{
+	cli();
+
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
+	for(;;);
+}
+
+void
+apus_power_off(void)
+{
+	for (;;);
+}
+
+void
+apus_halt(void)
+{
+   apus_restart(NULL);
+}
+
+void
+apus_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
+{
+        int old_level, new_level;
+
+	/* I don't think we need SMP code here - Corey */
+
+        old_level = ~(regs->mq) & IPLEMU_IPLMASK;
+        new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
+        if (new_level != 0)
+        {
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+                APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+                                          | (~(new_level) & IPLEMU_IPLMASK)));
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+
+                process_int (VEC_SPUR+new_level, regs);
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+                APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+                                          | (~(old_level) & IPLEMU_IPLMASK)));
+        }
+        APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+apus_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port, buf, ns);
+}
+
+void
+apus_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port, buf, ns);
+}
+
+int
+apus_ide_default_irq(ide_ioreg_t base)
+{
+        m68k_ide_default_irq(base);
+}
+
+ide_ioreg_t
+apus_ide_default_io_base(int index)
+{
+        m68k_ide_default_io_base(index);
+}
+
+int
+apus_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return m68k_ide_check_region(from, extent);
+}
+
+void
+apus_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        m68k_ide_request_region(from, extent, name);
+}
+
+void
+apus_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        m68k_ide_release_region(from, extent);
+}
+
+void
+apus_ide_fix_driveid(struct hd_driveid *id)
+{
+        m68k_ide_fix_driveid(id);
+}
+
+__initfunc(void
+apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+{
+        m68k_ide_init_hwif_ports(p, base, irq);
+}
+#endif
+
+__initfunc(void
+apus_local_init_IRQ(void))
+{
+	ppc_md.mask_irq = amiga_disable_irq;
+	ppc_md.unmask_irq = amiga_enable_irq;
+	apus_init_IRQ();
+}
+
+__initfunc(void
+apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+	/* Parse bootinfo. The bootinfo is located right after
+           the kernel bss */
+	parse_bootinfo((const struct bi_record *)&_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* Take care of initrd if we have one. Use data from
+	   bootinfo to avoid the need to initialize PPC
+	   registers when kernel is booted via a PPC reset. */
+	if ( ramdisk.addr ) {
+		initrd_start = (unsigned long) __va(ramdisk.addr);
+		initrd_end = (unsigned long) 
+			__va(ramdisk.size + ramdisk.addr);
+	}
+	/* Make sure code below is not executed. */
+	r4 = 0;
+	r6 = 0;
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+
+	ppc_md.setup_arch     = apus_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = apus_get_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = apus_init_IRQ;
+	ppc_md.do_IRQ         = apus_do_IRQ;
+	ppc_md.get_irq_source = NULL;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = apus_restart;
+	ppc_md.power_off      = apus_power_off;
+	ppc_md.halt           = apus_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = apus_set_rtc_time;
+	ppc_md.get_rtc_time   = apus_get_rtc_time;
+	ppc_md.calibrate_decr = apus_calibrate_decr;
+
+	/* These should not be used for the APUS yet, since it uses
+	   the M68K keyboard now. */
+	ppc_md.kbd_setkeycode    = NULL;
+	ppc_md.kbd_getkeycode    = NULL;
+	ppc_md.kbd_translate     = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds          = NULL;
+	ppc_md.kbd_init_hw       = NULL;
+	ppc_md.kbd_sysrq_xlate	 = NULL;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = apus_ide_insw;
+        ppc_ide_md.outsw = apus_ide_outsw;
+        ppc_ide_md.default_irq = apus_ide_default_irq;
+        ppc_ide_md.default_io_base = apus_ide_default_io_base;
+        ppc_ide_md.check_region = apus_ide_check_region;
+        ppc_ide_md.request_region = apus_ide_request_region;
+        ppc_ide_md.release_region = apus_ide_release_region;
+        ppc_ide_md.fix_driveid = apus_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
X }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.2.7/linux/arch/ppc/kernel/chrp_pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Tue May 11 08:24:32 1999
@@ -15,10 +15,14 @@
X #include <asm/hydra.h>
X #include <asm/prom.h>
X #include <asm/gg2.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
X 
X /* LongTrail */
X #define pci_config_addr(bus, dev, offset) \
-	(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
+(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
X 
X volatile struct Hydra *Hydra = NULL;
X 
@@ -30,159 +34,78 @@
X int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
X 				 unsigned char offset, unsigned char *val)
X {
-    if (bus > 7) {
-	*val = 0xff;
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    }
-    *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7) {
+		*val = 0xff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	*val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
+	return PCIBIOS_SUCCESSFUL;
X }
X 
X int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
X 				 unsigned char offset, unsigned short *val)
X {
-    if (bus > 7) {
-	*val = 0xffff;
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    }
-    *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7) {
+		*val = 0xffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	*val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
+	return PCIBIOS_SUCCESSFUL;
X }
X 
X 
X int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
X 				  unsigned char offset, unsigned int *val)
X {
-    if (bus > 7) {
-	*val = 0xffffffff;
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    }
-    *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	*val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
+	return PCIBIOS_SUCCESSFUL;
X }
X 
X int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
X 				  unsigned char offset, unsigned char val)
X {
-    if (bus > 7)
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
+	return PCIBIOS_SUCCESSFUL;
X }
X 
X int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
X 				  unsigned char offset, unsigned short val)
X {
-    if (bus > 7)
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
+	return PCIBIOS_SUCCESSFUL;
X }
X 
X int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
X 				   unsigned char offset, unsigned int val)
X {
-   if (bus > 7)
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
-    return PCIBIOS_SUCCESSFUL;
-}
-
-extern volatile unsigned int *pci_config_address;
-extern volatile unsigned char *pci_config_data;
-
-#define DEV_FN_MAX (31<<3)
-
-int raven_pcibios_read_config_byte(unsigned char bus, 
-                                      unsigned char dev_fn,
-                                      unsigned char offset, 
-                                      unsigned char *val)
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        *val = in_8(pci_config_data+(offset&3));
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_read_config_word(unsigned char bus, 
-                                      unsigned char dev_fn,
-                                      unsigned char offset, 
-                                      unsigned short *val)
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        *val = in_le16((volatile unsigned short *)
-                       (pci_config_data+(offset&3)));
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_read_config_dword(unsigned char bus, 
-                                       unsigned char dev_fn,
-                                       unsigned char offset, 
-                                       unsigned int *val)
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
-        *val = in_le32((volatile unsigned int *)(pci_config_data));
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_write_config_byte(unsigned char bus, 
-                                       unsigned char dev_fn,
-                                       unsigned char offset, 
-                                       unsigned char val) 
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        out_8(pci_config_data+(offset&3),val);
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_write_config_word(unsigned char bus, 
-                                       unsigned char dev_fn,
-                                       unsigned char offset, 
-                                       unsigned short val) 
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val);
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_write_config_dword(unsigned char bus, 
-                                        unsigned char dev_fn,
-                                        unsigned char offset, 
-                                        unsigned int val) 
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
-        out_le32((volatile unsigned int *)pci_config_data,val);
-        return PCIBIOS_SUCCESSFUL;
+	if (bus > 7)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
+	return PCIBIOS_SUCCESSFUL;
X }
X 
X #define python_config_address(bus) (unsigned *)((0xfef00000+0xf8000)-(bus*0x100000))
X #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
-#define PYTHON_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
+#define PYTHON_CFA(b, d, o)	(0x80 | ((b<<6) << 8) | ((d) << 16) \
X 				 | (((o) & ~3) << 24))
-     
+unsigned int python_busnr = 1;
+
X int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
X 				    unsigned char offset, unsigned char *val)
X {
-	if (bus > 2) {
+	if (bus > python_busnr) {
X 		*val = 0xff;
X 		return PCIBIOS_DEVICE_NOT_FOUND;
X 	}
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
X 	*val = in_8((unsigned char *)python_config_data(bus) + (offset&3));
X 	return PCIBIOS_SUCCESSFUL;
X }
@@ -190,11 +113,11 @@
X int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
X 				    unsigned char offset, unsigned short *val)
X {
-	if (bus > 2) {
+	if (bus > python_busnr) {
X 		*val = 0xffff;
X 		return PCIBIOS_DEVICE_NOT_FOUND;
X 	}
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
X 	*val = in_le16((unsigned short *)(python_config_data(bus) + (offset&3)));
X 	return PCIBIOS_SUCCESSFUL;
X }
@@ -203,11 +126,11 @@
X int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
X 				     unsigned char offset, unsigned int *val)
X {
-	if (bus > 2) {
+	if (bus > python_busnr) {
X 		*val = 0xffffffff;
X 		return PCIBIOS_DEVICE_NOT_FOUND;
X 	}
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
X 	*val = in_le32((unsigned *)python_config_data(bus));
X 	return PCIBIOS_SUCCESSFUL;
X }
@@ -215,9 +138,9 @@
X int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
X 				     unsigned char offset, unsigned char val)
X {
-	if (bus > 2)
+	if (bus > python_busnr)
X 		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
X 	out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val);
X 	return PCIBIOS_SUCCESSFUL;
X }
@@ -225,9 +148,9 @@
X int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
X 				     unsigned char offset, unsigned short val)
X {
-	if (bus > 2)
+	if (bus > python_busnr)
X 		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
X 	out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3),
X 		 val);
X 	return PCIBIOS_SUCCESSFUL;
@@ -236,9 +159,9 @@
X int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
X 				      unsigned char offset, unsigned int val)
X {
-	if (bus > 2)
+	if (bus > python_busnr)
X 		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
X 	out_le32((unsigned *)python_config_data(bus) + (offset&3), val);
X 	return PCIBIOS_SUCCESSFUL;
X }
@@ -264,7 +187,8 @@
X     	/* all others are 1 (= default) */
X };
X 
-__initfunc(int hydra_init(void))
+int __init
+hydra_init(void)
X {
X 	struct device_node *np;
X 
@@ -287,4 +211,97 @@
X 	OpenPIC_InitSenses = hydra_openpic_initsenses;
X 	OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses);
X 	return 1;
+}
+
+void __init
+chrp_pcibios_fixup(void)
+{
+	struct pci_dev *dev;
+	
+	/* some of IBM chrps have > 1 bus */
+	if ( !strncmp("IBM", get_property(find_path_device("/"),
+					 "name", NULL),3) )
+	{
+		pci_scan_peer_bridge(1);
+		pci_scan_peer_bridge(2);
+	}
+	
+	/* PCI interrupts are controlled by the OpenPIC */
+	for( dev=pci_devices ; dev; dev=dev->next )
+	{
+		if ( dev->irq )
+			dev->irq = openpic_to_irq( dev->irq );
+		/* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
+		if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
+			dev->base_address[0] += (dev->bus->number*0x08000000);
+		/* these need to be absolute addrs for OF and Matrox FB -- Cort */
+		if ( dev->vendor == PCI_VENDOR_ID_MATROX )
+		{
+			if ( dev->base_address[0] < isa_mem_base )
+				dev->base_address[0] += isa_mem_base;
+			if ( dev->base_address[1] < isa_mem_base )
+				dev->base_address[1] += isa_mem_base;
+		}
+		/* the F50 identifies the amd as a trident */
+		if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) &&
+		      (dev->class == PCI_CLASS_NETWORK_ETHERNET) )
+		{
+			dev->vendor = PCI_VENDOR_ID_AMD;
+			pcibios_write_config_word(dev->bus->number, dev->devfn,
+						   PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+		}
+	}
+}
+
+decl_config_access_method(grackle);
+decl_config_access_method(indirect);
+
+void __init
+chrp_setup_pci_ptrs(void)
+{
+	struct device_node *py;
+	
+        if ( !strncmp("MOT",
+                      get_property(find_path_device("/"), "model", NULL),3) )
+        {
+                pci_dram_offset = 0;
+                isa_mem_base = 0xf7000000;
+                isa_io_base = 0xfe000000;
+                set_config_access_method(grackle);
+        }
+        else
+        {
+		if ( (py = find_compatible_devices( "pci", "IBM,python" )) )
+		{
+			/* find out how many pythons */
+			while ( (py = py->next) ) python_busnr++;
+                        set_config_access_method(python);
+			/*
+			 * We base these values on the machine type but should
+			 * try to read them from the python controller itself.
+			 * -- Cort
+			 */
+			if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) )
+			{
+				pci_dram_offset = 0x80000000;
+				isa_mem_base = 0xa0000000;
+				isa_io_base = 0x88000000;
+			} else if ( !strncmp("IBM,7043-260",
+			   get_property(find_path_device("/"), "name", NULL),12) )
+			{
+				pci_dram_offset = 0x80000000;
+				isa_mem_base = 0xc0000000;
+				isa_io_base = 0xf8000000;
+			}
+                }
+                else
+                {
+			pci_dram_offset = 0;
+			isa_mem_base = 0xf7000000;
+			isa_io_base = 0xf8000000;
+			set_config_access_method(gg2);
+                }
+        }
+	
+	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
X }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.2.7/linux/arch/ppc/kernel/chrp_setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Tue May 11 08:24:32 1999
@@ -41,8 +41,50 @@
X #include <asm/prom.h>
X #include <asm/gg2.h>
X #include <asm/pci-bridge.h>
-
-extern void hydra_init(void);
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/adb.h>
+#include <asm/hydra.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
+
+/* Fixme - need to move these into their own .c and .h file */
+extern void i8259_mask_and_ack_irq(unsigned int irq_nr);
+extern void i8259_set_irq_mask(unsigned int irq_nr);
+extern void i8259_mask_irq(unsigned int irq_nr);
+extern void i8259_unmask_irq(unsigned int irq_nr);
+extern void i8259_init(void);
+
+/* Fixme - remove this when it is fixed. - Corey */
+extern volatile unsigned char *chrp_int_ack_special;
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+void chrp_time_init(void);
+
+void chrp_setup_pci_ptrs(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			    char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+extern unsigned char mackbd_sysrq_xlate[128];
X 
X /* for the mac fs */
X kdev_t boot_dev;
@@ -61,17 +103,17 @@
X #endif
X 
X static const char *gg2_memtypes[4] = {
-    "FPM", "SDRAM", "EDO", "BEDO"
+	"FPM", "SDRAM", "EDO", "BEDO"
X };
X static const char *gg2_cachesizes[4] = {
-    "256 KB", "512 KB", "1 MB", "Reserved"
+	"256 KB", "512 KB", "1 MB", "Reserved"
X };
X static const char *gg2_cachetypes[4] = {
-    "Asynchronous", "Reserved", "Flow-Through Synchronous",
-    "Pipelined Synchronous"
+	"Asynchronous", "Reserved", "Flow-Through Synchronous",
+	"Pipelined Synchronous"
X };
X static const char *gg2_cachemodes[4] = {
-    "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
X };
X 
X int
@@ -84,7 +126,7 @@
X 
X 	root = find_path_device("/");
X 	if (root)
-	    model = get_property(root, "model", NULL);
+		model = get_property(root, "model", NULL);
X 	len = sprintf(buffer,"machine\t\t: CHRP %s\n", model);
X 
X 	/* longtrail (goldengate) stuff */
@@ -137,7 +179,7 @@
X 	return len;
X }
X 
-    /*
+/*
X      *  Fixes for the National Semiconductor PC78308VUL SuperI/O
X      *
X      *  Some versions of Open Firmware incorrectly initialize the IRQ settings
@@ -146,56 +188,56 @@
X 
X __initfunc(static inline void sio_write(u8 val, u8 index))
X {
-    outb(index, 0x15c);
-    outb(val, 0x15d);
+	outb(index, 0x15c);
+	outb(val, 0x15d);
X }
X 
X __initfunc(static inline u8 sio_read(u8 index))
X {
-    outb(index, 0x15c);
-    return inb(0x15d);
+	outb(index, 0x15c);
+	return inb(0x15d);
X }
X 
X __initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level,
X 				     u8 type))
X {
-    u8 level0, type0, active;
+	u8 level0, type0, active;
X 
-    /* select logical device */
-    sio_write(device, 0x07);
-    active = sio_read(0x30);
-    level0 = sio_read(0x70);
-    type0 = sio_read(0x71);
-    printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
-	   !active ? "in" : "");
-    if (level0 == level && type0 == type && active)
-	printk("OK\n");
-    else {
-	printk("remapping to level %d, type %d, active\n", level, type);
-	sio_write(0x01, 0x30);
-	sio_write(level, 0x70);
-	sio_write(type, 0x71);
-    }
+	/* select logical device */
+	sio_write(device, 0x07);
+	active = sio_read(0x30);
+	level0 = sio_read(0x70);
+	type0 = sio_read(0x71);
+	printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
+	       !active ? "in" : "");
+	if (level0 == level && type0 == type && active)
+		printk("OK\n");
+	else {
+		printk("remapping to level %d, type %d, active\n", level, type);
+		sio_write(0x01, 0x30);
+		sio_write(level, 0x70);
+		sio_write(type, 0x71);
+	}
X 
X }
X 
X __initfunc(static void sio_init(void))
X {
-    /* logical device 0 (KBC/Keyboard) */
-    sio_fixup_irq("keyboard", 0, 1, 2);
-    /* select logical device 1 (KBC/Mouse) */
-    sio_fixup_irq("mouse", 1, 12, 2);
+	/* logical device 0 (KBC/Keyboard) */
+	sio_fixup_irq("keyboard", 0, 1, 2);
+	/* select logical device 1 (KBC/Mouse) */
+	sio_fixup_irq("mouse", 1, 12, 2);
X }
X 
X 
X __initfunc(void
-chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
+	   chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
X {
X 	extern char cmd_line[];
X 
X 	/* init to some ~sane value until calibrate_delay() runs */
X 	loops_per_sec = 50000000;
-	
+
X #ifdef CONFIG_BLK_DEV_INITRD
X 	/* this is fine for chrp */
X 	initrd_below_start_ok = 1;
@@ -243,27 +285,210 @@
X 	if ( !strncmp("MOT", get_property(find_path_device("/"),
X 					  "model", NULL),3) )
X 		*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+	/*
+	 * The f50 has a lot of IO space - we need to map some in that
+	 * isn't covered by the BAT mappings in MMU_init() -- Cort
+	 */
+	if ( !strncmp("F5", get_property(find_path_device("/"),
+					 "ibm,model-class", NULL),2) )
+	{
+#if 0		
+		/*
+		 * This ugly hack allows us to force ioremap() to
+		 * create a 1-to-1 mapping for us, even though
+		 * the address is < ioremap_base.  This is necessary
+		 * since we want our PCI IO space to have contiguous
+		 * virtual addresses and I think it's worse to have
+		 * calls to map_page() here.
+		 * -- Cort
+		 */
+		unsigned long hold = ioremap_base;
+		ioremap_base = 0;
+		__ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE);
+		ioremap_base = hold;
+#endif		
+	}
X }
X 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+void
+chrp_restart(char *cmd)
+{
+#if 0
+	extern unsigned int rtas_entry, rtas_data, rtas_size;
+	printk("RTAS system-reboot returned %d\n",
+	       call_rtas("system-reboot", 0, 1, NULL));
+	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+	       rtas_entry,rtas_data,rtas_size);
+	for (;;);
+#else
+	printk("System Halted\n");
+	while(1);
+#endif
+}
X 
-unsigned int chrp_ide_irq = 0;
-int chrp_ide_ports_known = 0;
-ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-ide_ioreg_t chrp_idedma_regbase;
+void
+chrp_power_off(void)
+{
+	/* RTAS doesn't seem to work on Longtrail.
+	   For now, do it the same way as the PReP. */
+#if 0
+	extern unsigned int rtas_entry, rtas_data, rtas_size;
+	printk("RTAS power-off returned %d\n",
+	       call_rtas("power-off", 2, 1, NULL, 0, 0));
+	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+	       rtas_entry,rtas_data,rtas_size);
+	for (;;);
+#else
+	chrp_restart(NULL);
+#endif
+}
X 
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+chrp_halt(void)
X {
-        ide_ioreg_t port = base;
-        int i = 8;
+	chrp_restart(NULL);
+}
X 
-        while (i--)
-                *p++ = port++;
-        *p++ = port;
-        if (irq != NULL)
-                *irq = chrp_ide_irq;
+u_int
+chrp_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+void
+chrp_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
+{
+        int irq;
+        unsigned long bits = 0;
+        int openpic_eoi_done = 0;
+
+#ifdef __SMP__
+        {
+                unsigned int loops = 1000000;
+                while (test_bit(0, &global_irq_lock)) {
+                        if (smp_processor_id() == global_irq_holder) {
+                                printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                                break;
+                        }
+                        if (loops-- == 0) {
+                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                        }
+                }
+        }
+#endif /* __SMP__ */
+
+        irq = openpic_irq(0);
+        if (irq == IRQ_8259_CASCADE)
+        {
+                /*
+                 * This magic address generates a PCI IACK cycle.
+                 *
+                 * This should go in the above mask/ack code soon. -- Cort
+                 */
+		if ( chrp_int_ack_special )
+			irq = *chrp_int_ack_special;
+		else
+			irq = i8259_irq(0);
+                /*
+                 * Acknowledge as soon as possible to allow i8259
+                 * interrupt nesting                         */
+                openpic_eoi(0);
+                openpic_eoi_done = 1;
+        }
+        if (irq == OPENPIC_VEC_SPURIOUS)
+        {
+                /*
+                 * Spurious interrupts should never be
+                 * acknowledged
+                 */
+                ppc_spurious_interrupts++;
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 08'
echo 'File patch-2.2.8 is continued in part 09'
echo 09 > _shar_seq_.tmp
#!/bin/sh
# this is part 09 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 09; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+                openpic_eoi_done = 1;
+		goto out;
+        }
+        bits = 1UL << irq;
+
+        if (irq < 0)
+        {
+                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                ppc_spurious_interrupts++;
+        }
+	else
+        {
+		ppc_irq_dispatch_handler( regs, irq );
+	}
+out:
+        if (!openpic_eoi_done)
+                openpic_eoi(0);
X }
X 
+__initfunc(void
+	   chrp_init_IRQ(void))
+{
+	struct device_node *np;
+	int i;
+
+	if ( !(np = find_devices("pci") ) )
+		printk("Cannot find pci to get ack address\n");
+	else
+	{
+		chrp_int_ack_special = (volatile unsigned char *)
+			(*(unsigned long *)get_property(np,
+							"8259-interrupt-acknowledge", NULL));
+	}
+	for ( i = 16 ; i < NR_IRQS ; i++ )
+		irq_desc[i].ctl = &open_pic;
+	/* openpic knows that it's at irq 16 offset
+	 * so we don't need to set it in the pic structure
+	 * -- Cort
+	 */
+	openpic_init(1);
+	for ( i = 0 ; i < 16  ; i++ )
+		irq_desc[i].ctl = &i8259_pic;
+	i8259_init();
+#ifdef CONFIG_XMON
+	request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+		    xmon_irq, 0, "NMI", 0);
+#endif	/* CONFIG_XMON */
+#ifdef __SMP__
+	request_irq(openpic_to_irq(OPENPIC_VEC_IPI),
+		    openpic_ipi_action, 0, "IPI0", 0);
+#endif	/* __SMP__ */
+}
+
+__initfunc(void
+	   chrp_init2(void))
+{
+	adb_init();
+
+	/* Should this be here? - Corey */
+	pmac_nvram_init();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+unsigned int chrp_ide_irq = 0;
+int chrp_ide_ports_known = 0;
+ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+ide_ioreg_t chrp_idedma_regbase;
+
X void chrp_ide_probe(void) {
X 
X         struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
@@ -281,9 +506,167 @@
X         }
X }
X 
+void
+chrp_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port+_IO_BASE, buf, ns);
+}
+
+void
+chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+chrp_ide_default_irq(ide_ioreg_t base)
+{
+        if (chrp_ide_ports_known == 0)
+	        chrp_ide_probe();
+	return chrp_ide_irq;
+}
+
+ide_ioreg_t
+chrp_ide_default_io_base(int index)
+{
+        if (chrp_ide_ports_known == 0)
+	        chrp_ide_probe();
+	return chrp_ide_regbase[index];
+}
+
+int
+chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+void
+chrp_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+void
+chrp_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+void
+chrp_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+        ide_ioreg_t port = base;
+        int i = 8;
+
+        while (i--)
+                *p++ = port++;
+        *p++ = port;
+        if (irq != NULL)
+                *irq = chrp_ide_irq;
+}
+
X EXPORT_SYMBOL(chrp_ide_irq);
X EXPORT_SYMBOL(chrp_ide_ports_known);
X EXPORT_SYMBOL(chrp_ide_regbase);
X EXPORT_SYMBOL(chrp_ide_probe);
X 
X #endif
+
+__initfunc(void
+	   chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		     unsigned long r6, unsigned long r7))
+{
+	chrp_setup_pci_ptrs();
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r3 )
+	{
+		initrd_start = r3 + KERNELBASE;
+		initrd_end = r3 + r4 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+        /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	ppc_md.setup_arch     = chrp_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
+	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
+	ppc_md.init_IRQ       = chrp_init_IRQ;
+	ppc_md.do_IRQ         = chrp_do_IRQ;
+		
+	ppc_md.init           = chrp_init2;
+
+	ppc_md.restart        = chrp_restart;
+	ppc_md.power_off      = chrp_power_off;
+	ppc_md.halt           = chrp_halt;
+
+	ppc_md.time_init      = chrp_time_init;
+	ppc_md.set_rtc_time   = chrp_set_rtc_time;
+	ppc_md.get_rtc_time   = chrp_get_rtc_time;
+	ppc_md.calibrate_decr = chrp_calibrate_decr;
+
+#ifdef CONFIG_VT
+#ifdef CONFIG_MAC_KEYBOAD
+	if ( adb_hardware == ADB_NONE )
+	{
+		ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+		ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+		ppc_md.kbd_translate     = pckbd_translate;
+		ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+		ppc_md.kbd_leds          = pckbd_leds;
+		ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+		ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif		
+	}
+	else
+	{
+		ppc_md.kbd_setkeycode    = mackbd_setkeycode;
+		ppc_md.kbd_getkeycode    = mackbd_getkeycode;
+		ppc_md.kbd_translate     = mackbd_translate;
+		ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
+		ppc_md.kbd_leds          = mackbd_leds;
+		ppc_md.kbd_init_hw       = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+		ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+#endif		
+	}
+#else
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = chrp_ide_insw;
+        ppc_ide_md.outsw = chrp_ide_outsw;
+        ppc_ide_md.default_irq = chrp_ide_default_irq;
+        ppc_ide_md.default_io_base = chrp_ide_default_io_base;
+        ppc_ide_md.check_region = chrp_ide_check_region;
+        ppc_ide_md.request_region = chrp_ide_request_region;
+        ppc_ide_md.release_region = chrp_ide_release_region;
+        ppc_ide_md.fix_driveid = chrp_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.2.7/linux/arch/ppc/kernel/head.S	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/head.S	Tue May 11 08:24:32 1999
@@ -1,7 +1,7 @@
X /*
X  *  arch/ppc/kernel/head.S
X  *
- *  $Id: head.S,v 1.121 1999/03/16 10:40:29 cort Exp $
+ *  $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
X  *
X  *  PowerPC version 
X  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -91,7 +91,7 @@
X #define tlbia \
X 	li	r4,128; \
X 	mtctr	r4; \
-	lis	r4,0xC000; \
+	lis	r4,KERNELBASE@h; \
X 0:	tlbie	r4; \
X 	addi	r4,r4,0x1000; \
X 	bdnz	0b
@@ -415,7 +415,7 @@
X  * this, we leave this much untouched space on the stack on exception
X  * entry.
X  */
-#define STACK_UNDERHEAD	64
+#define STACK_UNDERHEAD	0
X 	
X /*
X  * Exception entry code.  This code runs with address translation
@@ -1495,27 +1495,25 @@
X  * On SMP we know the fpu is free, since we give it up every
X  * switch.  -- Cort
X  */
+	mfmsr	r5
+	ori	r5,r5,MSR_FP
+	SYNC
+	mtmsr	r5			/* enable use of fpu now */
+	SYNC
+/*
+ * For SMP, we don't do lazy FPU switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_fpu in switch_to.
+ */
+#ifndef __SMP__
X #ifndef CONFIG_APUS
X 	lis	r6,-KERNELBASE@h
X #else
X 	lis	r6,CYBERBASEp@h
X 	lwz	r6,0(r6)
X #endif
-
X 	addis	r3,r6,last_task_used_math@ha
X 	lwz	r4,last_task_used_math@l(r3)
-	mfmsr	r5
-	ori	r5,r5,MSR_FP
-	SYNC
-	mtmsr	r5			/* enable use of fpu now */
-/*
- * All the saving of last_task_used_math is handled
- * by a switch_to() call to smp_giveup_fpu() in SMP so 
- * last_task_used_math is not used.
- * -- Cort
- */
-#ifndef __SMP__
-	SYNC
X 	cmpi	0,r4,0
X 	beq	1f
X 	add	r4,r4,r6
@@ -1529,15 +1527,17 @@
X 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
X 	andc	r4,r4,r20		/* disable FP for previous task */
X 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
X #endif /* __SMP__ */
-1:	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1	/* enable use of FP after return */
+	/* enable use of FP after return */
+	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
X 	mfspr	r5,SPRG3		/* current task's TSS (phys) */
X 	lfd	fr0,TSS_FPSCR-4(r5)
X 	mtfsf	0xff,fr0
X 	REST_32FPRS(0, r5)
+#ifndef __SMP__
X 	subi	r4,r5,TSS
X 	sub	r4,r4,r6
-#ifndef __SMP__
X 	stw	r4,last_task_used_math@l(r3)
X #endif /* __SMP__ */
X 	/* restore registers and return */
@@ -1574,48 +1574,44 @@
X 	.align	4
X 
X /*
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
+ * giveup_fpu(tsk)
+ * Disable FP for the task given as the argument,
+ * and save the floating-point registers in its thread_struct.
X  * Enables the FPU for use in the kernel on return.
X  */
-/* smp_giveup_fpu() takes an arg to tell it where to save the fpu
- * regs since last_task_used_math can't be trusted (many many race
- * conditions). -- Cort
- */
-	.globl	smp_giveup_fpu
-smp_giveup_fpu:	
-	mr	r4,r3
-	b	12f
X 	.globl	giveup_fpu
X giveup_fpu:
-	lis	r3,last_task_used_math@ha
-	lwz	r4,last_task_used_math@l(r3)
-12:		
X 	mfmsr	r5
X 	ori	r5,r5,MSR_FP
X 	SYNC
X 	mtmsr	r5			/* enable use of fpu now */
X 	SYNC
-	cmpi	0,r4,0
+	cmpi	0,r3,0
X 	beqlr-				/* if no previous owner, done */
-	addi	r4,r4,TSS	        /* want TSS of last_task_used_math */
+	addi	r3,r3,TSS	        /* want TSS of task */
+	lwz	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32FPRS(0, r3)
+	mffs	fr0
+	stfd	fr0,TSS_FPSCR-4(r3)
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r3,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r3		/* disable FP for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
X #ifndef __SMP__
X 	li	r5,0
-	stw	r5,last_task_used_math@l(r3)
+	lis	r4,last_task_used_math@ha
+	stw	r5,last_task_used_math@l(r4)
X #endif /* __SMP__ */
-	SAVE_32FPRS(0, r4)
-	mffs	fr0
-	stfd	fr0,TSS_FPSCR-4(r4)
-	lwz	r5,PT_REGS(r4)
-	lwz	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
-	li	r4,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r3,r3,r4		/* disable FP for previous task */
-	stw	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+	blr
+
X #else  /* CONFIG_8xx */
X 	.globl	giveup_fpu
X giveup_fpu:
-#endif /* CONFIG_8xx */
X 	blr
+#endif /* CONFIG_8xx */
X 
X /*
X  * This code is jumped to from the startup code to copy
@@ -2049,8 +2045,9 @@
X 	stw	r0,GPR0(r1)
X 	lwz	r0,0(r1)
X 	stw	r0,GPR1(r1)
-	SAVE_10GPRS(2, r1)
-	SAVE_10GPRS(12, r1)
+	/* r3-r13 are caller saved -- Cort */
+	SAVE_GPR(2, r1)
+	SAVE_8GPRS(14, r1)
X 	SAVE_10GPRS(22, r1)
X 	mflr	r20		/* Return to switch caller */
X 	mfmsr	r22
@@ -2073,6 +2070,8 @@
X 	mtspr	SPRG3,r0	/* Update current TSS phys addr */
X 	SYNC
X 	lwz	r1,KSP(r4)	/* Load new stack pointer */
+	/* save the old current 'last' for return value */
+	mr	r3,r2
X 	addi	r2,r4,-TSS	/* Update current */
X #ifndef CONFIG_8xx
X 	/* Set up segment registers for new task */
@@ -2080,39 +2079,62 @@
X 	addis	r5,r5,0x6000	/* Set Ks, Ku bits */
X 	li	r0,12		/* TASK_SIZE / SEGMENT_SIZE */
X 	mtctr	r0
-	li	r3,0
-3:	mtsrin	r5,r3
+	li	r9,0
+3:	mtsrin	r5,r9
X 	addi	r5,r5,1		/* next VSID */
-	addis	r3,r3,0x1000	/* address of next segment */
+	addis	r9,r9,0x1000	/* address of next segment */
X 	bdnz	3b
X #else
X /* On the MPC8xx, we place the physical address of the new task
X  * page directory loaded into the MMU base register, and set the
X  * ASID compare register with the new "context".
X  */
-        lwz     r3,MM-TSS(r4)           /* Get virtual address of mm */
-        lwz     r3,PGD(r3)              /* get new->mm->pgd */
-        addis   r3,r3,-KERNELBASE@h     /* convert to phys addr */
-        mtspr   M_TWB, r3               /* Update MMU base address */
+        lwz     r9,MM-TSS(r4)           /* Get virtual address of mm */
+        lwz     r9,PGD(r9)              /* get new->mm->pgd */
+        addis   r9,r9,-KERNELBASE@h     /* convert to phys addr */
+        mtspr   M_TWB, r9               /* Update MMU base address */
X         mtspr   M_CASID, r5             /* Update context */
X         tlbia
X #endif
X 	SYNC
-
-/* FALL THROUGH into int_return */
-#ifdef __SMP__
-	/* call schedule_tail if this is the first time for a child process */
-	lwz	r5,TSS_SMP_FORK_RET(r4)
-	cmpi	0,r5,0
-	beq+	int_return
-	li	r3,0
-	stw	r3,TSS_SMP_FORK_RET(r4)
-	bl	schedule_tail
-#endif /* __SMP__ */
+2:	lwz	r9,_MSR(r1)	/* Returning to user mode? */
+	andi.	r9,r9,MSR_PR
+	beq+	10f		/* if not, don't adjust kernel stack */
+8:	addi	r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD	/* size of frame */
+	stw	r4,TSS+KSP(r2)	/* save kernel stack pointer */
+	tophys(r9,r1,r9)
+	mtspr	SPRG2,r9	/* phys exception stack pointer */
+10:	lwz	r2,_CTR(r1)
+	lwz	r0,_LINK(r1)
+	mtctr	r2
+	mtlr	r0
+	lwz	r2,_XER(r1)
+	lwz	r0,_CCR(r1)
+	mtspr	XER,r2
+	mtcrf	0xFF,r0
+	/* r3-r13 are destroyed -- Cort */
+	REST_GPR(14, r1)
+	REST_8GPRS(15, r1)
+	REST_8GPRS(23, r1)
+	REST_GPR(31, r1)
+	lwz	r2,_NIP(r1)	/* Restore environment */
+	lwz	r0,_MSR(r1)
+	mtspr	SRR0,r2
+	mtspr	SRR1,r0
+	lwz	r0,GPR0(r1)
+	lwz	r2,GPR2(r1)
+	lwz	r1,GPR1(r1)
+	SYNC
+	rfi
X 
X /*
X  * Trap exit.
X  */
+#ifdef __SMP__	
+	.globl	ret_from_smpfork
+ret_from_smpfork:
+	bl	schedule_tail
+#endif	
X 	.globl	ret_from_syscall
X ret_from_syscall:	
X 	.globl	int_return
@@ -2127,8 +2149,8 @@
X 	lwz	r5,_MSR(r1)
X 	and.	r5,r5,r4
X 	beq	2f
-3:	lis	r4,n_lost_interrupts@ha
-	lwz	r4,n_lost_interrupts@l(r4)
+3:	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
X 	cmpi	0,r4,0
X 	beq+	1f
X 	addi	r3,r1,STACK_FRAME_OVERHEAD
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/i8259.c linux/arch/ppc/kernel/i8259.c
--- v2.2.7/linux/arch/ppc/kernel/i8259.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/i8259.c	Tue May 11 08:24:32 1999
@@ -0,0 +1,130 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include "i8259.h"
+
+unsigned char cached_8259[2] = { 0xff, 0xff };
+#define cached_A1 (cached_8259[0])
+#define cached_21 (cached_8259[1])
+
+int i8259_irq(int cpu)
+{
+	int irq;
+	
+        /*
+         * Perform an interrupt acknowledge cycle on controller 1
+         */                                                             
+        outb(0x0C, 0x20);
+        irq = inb(0x20) & 7;                                   
+        if (irq == 2)                                                     
+        {                                                                   
+                /*                                     
+                 * Interrupt is cascaded so perform interrupt
+                 * acknowledge on controller 2
+                 */
+                outb(0x0C, 0xA0);                      
+                irq = (inb(0xA0) & 7) + 8;
+        }
+        else if (irq==7)                                
+        {
+                /*                               
+                 * This may be a spurious interrupt
+                 *                         
+                 * Read the interrupt status register. If the most
+                 * significant bit is not set then there is no valid
+		 * interrupt
+		 */
+		outb(0x0b, 0x20);
+		if(~inb(0x20)&0x80)
+			return -1;
+	}
+	return irq;
+}
+
+static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+        if ( irq_nr >= i8259_pic.irq_offset )
+                irq_nr -= i8259_pic.irq_offset;
+
+        if (irq_nr > 7) {                                                   
+                cached_A1 |= 1 << (irq_nr-8);                                   
+                inb(0xA1);      /* DUMMY */                                     
+                outb(cached_A1,0xA1);                                           
+                outb(0x20,0xA0);        /* Non-specific EOI */             
+                outb(0x20,0x20);        /* Non-specific EOI to cascade */
+        } else {                                                            
+                cached_21 |= 1 << irq_nr;                                   
+                inb(0x21);      /* DUMMY */                                 
+                outb(cached_21,0x21);
+                outb(0x20,0x20);        /* Non-specific EOI */                 
+        }                                                                
+}
+
+static void i8259_set_irq_mask(int irq_nr)
+{
+        outb(cached_A1,0xA1);
+        outb(cached_21,0x21);
+}
+
+static void i8259_mask_irq(unsigned int irq_nr)
+{
+        if ( irq_nr >= i8259_pic.irq_offset )
+                irq_nr -= i8259_pic.irq_offset;
+        if ( irq_nr < 8 )
+                cached_21 |= 1 << irq_nr;
+        else
+                cached_A1 |= 1 << (irq_nr-8);
+        i8259_set_irq_mask(irq_nr);
+}
+
+static void i8259_unmask_irq(unsigned int irq_nr)
+{
+
+        if ( irq_nr >= i8259_pic.irq_offset )
+                irq_nr -= i8259_pic.irq_offset;
+        if ( irq_nr < 8 )
+                cached_21 &= ~(1 << irq_nr);
+        else
+                cached_A1 &= ~(1 << (irq_nr-8));
+        i8259_set_irq_mask(irq_nr);
+}
+
+struct hw_interrupt_type i8259_pic = {
+        " i8259    ",
+        NULL,
+        NULL,
+        NULL,
+        i8259_unmask_irq,
+        i8259_mask_irq,
+        i8259_mask_and_ack_irq,
+        0
+};
+
+static void
+no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+void __init i8259_init(void)
+{
+        /* init master interrupt controller */
+        outb(0x11, 0x20); /* Start init sequence */
+        outb(0x00, 0x21); /* Vector base */
+        outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+        outb(0x01, 0x21); /* Select 8086 mode */
+        outb(0xFF, 0x21); /* Mask all */
+        /* init slave interrupt controller */
+        outb(0x11, 0xA0); /* Start init sequence */
+        outb(0x08, 0xA1); /* Vector base */
+        outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+        outb(0x01, 0xA1); /* Select 8086 mode */
+        outb(0xFF, 0xA1); /* Mask all */
+        outb(cached_A1, 0xA1);
+        outb(cached_21, 0x21);
+        request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
+                     "82c59 secondary cascade", NULL );
+        enable_irq(i8259_pic.irq_offset + 2);  /* Enable cascade interrupt */
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/i8259.h linux/arch/ppc/kernel/i8259.h
--- v2.2.7/linux/arch/ppc/kernel/i8259.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/i8259.h	Tue May 11 08:24:32 1999
@@ -0,0 +1,12 @@
+
+#ifndef _PPC_KERNEL_i8259_H
+#define _PPC_KERNEL_i8259_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type i8259_pic;
+
+void i8259_init(void);
+int i8259_irq(int);
+
+#endif /* _PPC_KERNEL_i8259_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.2.7/linux/arch/ppc/kernel/idle.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/idle.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: idle.c,v 1.60 1999/02/12 07:06:26 cort Exp $
+ * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $
X  *
X  * Idle daemon for PowerPC.  Idle daemon will handle any action
X  * that needs to be taken when the system becomes idle.
@@ -303,7 +303,14 @@
X 			hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
X 			hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
X 			asm("mtspr 1008,%0" : : "r" (hid0));
-			msr |= MSR_POW;
+		
+			/* set the POW bit in the MSR, and enable interrupts
+			 * so we wake up sometime! */
+			_nmask_and_or_msr(0, MSR_POW | MSR_EE);
+
+			/* Disable interrupts again so restore_flags will
+			 * work. */
+			_nmask_and_or_msr(MSR_EE, 0);
X 		}
X 		restore_flags(msr);
X 	default:
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/indirect_pci.c linux/arch/ppc/kernel/indirect_pci.c
--- v2.2.7/linux/arch/ppc/kernel/indirect_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/indirect_pci.c	Tue May 11 08:24:32 1999
@@ -0,0 +1,121 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned int * pci_config_address;
+unsigned char * pci_config_data;
+
+int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val)
+{
+	unsigned flags;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	*val= in_8(pci_config_data + (offset&3));
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val)
+{
+	unsigned flags;
+	
+	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	*val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int *val)
+{
+	unsigned flags;
+	
+	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	*val= in_le32((unsigned *)pci_config_data);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char val)
+{
+	unsigned flags;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	out_8(pci_config_data + (offset&3), val);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short val)
+{
+	unsigned flags;
+
+	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int val)
+{
+	unsigned flags;
+
+	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	out_le32((unsigned *)pci_config_data, val);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.2.7/linux/arch/ppc/kernel/irq.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/irq.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: irq.c,v 1.102 1999/02/03 01:36:59 paulus Exp $
+ * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
X  *
X  *  arch/ppc/kernel/irq.c
X  *
@@ -58,44 +58,15 @@
X #include <asm/amigahw.h>
X #include <asm/amigappc.h>
X #include <asm/ptrace.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mbx.h>
-#endif
X 
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+#include "local_irq.h"
+
X extern volatile unsigned long ipi_count;
-static void dispatch_handler(struct pt_regs *regs, int irq);
X void enable_irq(unsigned int irq_nr);
X void disable_irq(unsigned int irq_nr);
X 
-static void i8259_mask_and_ack_irq(unsigned int irq_nr);
-static void i8259_mask_irq(unsigned int irq_nr);
-static void i8259_unmask_irq(unsigned int irq_nr);
-#ifdef CONFIG_8xx
-static void mbx_mask_and_ack(unsigned int irq_nr);
-static void mbx_mask_irq(unsigned int irq_nr);
-static void mbx_unmask_irq(unsigned int irq_nr);
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
-#else /* CONFIG_8xx */
-static volatile unsigned char *chrp_int_ack_special;
-extern void process_int(unsigned long vec, struct pt_regs *fp);
-extern void apus_init_IRQ(void);
-extern void amiga_disable_irq(unsigned int irq);
-extern void amiga_enable_irq(unsigned int irq);
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs);
-static void pmac_mask_irq(unsigned int irq_nr);
-static void pmac_unmask_irq(unsigned int irq_nr);
-static void pmac_mask_and_ack_irq(unsigned int irq_nr);
-static void chrp_mask_and_ack_irq(unsigned int irq_nr);
-static void chrp_unmask_irq(unsigned int irq_nr);
-static void chrp_mask_irq(unsigned int irq_nr);
-#ifdef __SMP__	
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_message_recv(void);
-#endif /* __SMP__ */
-#endif /* CONFIG_8xx */
+/* Fixme - Need to figure out a way to get rid of this - Corey */
+volatile unsigned char *chrp_int_ack_special;
X 
X #ifdef CONFIG_APUS
X /* Rename a few functions. Requires the CONFIG_APUS protection. */
@@ -105,39 +76,19 @@
X #define VEC_SPUR    (24)
X #endif
X 
+#define MAXCOUNT 10000000
+
X #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
-unsigned char cached_8259[2] = { 0xff, 0xff };
-#define cached_A1 (cached_8259[0])
-#define cached_21 (cached_8259[1])
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-int max_irqs;
-int max_real_irqs;
-static int spurious_interrupts = 0;
-static unsigned int cached_irq_mask[NR_MASK_WORDS];
-unsigned int lost_interrupts[NR_MASK_WORDS];
-atomic_t n_lost_interrupts;
-
-#ifndef CONFIG_8xx
-#define GATWICK_IRQ_POOL_SIZE	10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
-/* pmac */
-struct pmac_irq_hw {
-	unsigned int	flag;
-	unsigned int	enable;
-	unsigned int	ack;
-	unsigned int	level;
-};
-
-/* these addresses are obtained from the device tree now -- Cort */
-volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmac = {
-	(struct pmac_irq_hw *) 0xf3000020,
-	(struct pmac_irq_hw *) 0xf3000010,
-	(struct pmac_irq_hw *) 0xf4000020,
-	(struct pmac_irq_hw *) 0xf4000010,
-};
-#endif /* CONFIG_8xx */
+
+int ppc_spurious_interrupts = 0;
+
+unsigned int ppc_local_bh_count[NR_CPUS];
+unsigned int ppc_local_irq_count[NR_CPUS];
+struct irqaction *ppc_irq_action[NR_IRQS];
+unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+atomic_t ppc_n_lost_interrupts;
+
X 
X /* nasty hack for shared irq's since we need to do kmalloc calls but
X  * can't very early in the boot when we need to do a request irq.
@@ -174,82 +125,7 @@
X 	kfree(ptr);
X }
X 
-struct hw_interrupt_type {
-	const char * typename;
-	void (*startup)(unsigned int irq);
-	void (*shutdown)(unsigned int irq);
-	void (*handle)(unsigned int irq, struct pt_regs * regs);
-	void (*enable)(unsigned int irq);
-	void (*disable)(unsigned int irq);
-	void (*mask_and_ack)(unsigned int irq);
-	int irq_offset;
-};
-
-#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
-#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
-#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
-
-struct irqdesc {
-	struct irqaction *action;
-	struct hw_interrupt_type *ctl;
-};
-static struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-
-static struct hw_interrupt_type i8259_pic = {
-	" i8259    ",
-	NULL,
-	NULL,
-	NULL,
-	i8259_unmask_irq,
-	i8259_mask_irq,
-	i8259_mask_and_ack_irq,
-	0
-};
-#ifndef CONFIG_8xx
-static struct hw_interrupt_type pmac_pic = {
-	" PMAC-PIC ",
-	NULL,
-	NULL,
-	NULL,
-	pmac_unmask_irq,
-	pmac_mask_irq,
-	pmac_mask_and_ack_irq,
-	0
-};
-
-static struct hw_interrupt_type gatwick_pic = {
-	" GATWICK  ",
-	NULL,
-	NULL,
-	NULL,
-	pmac_unmask_irq,
-	pmac_mask_irq,
-	pmac_mask_and_ack_irq,
-	0
-};
-
-static struct hw_interrupt_type open_pic = {
-	" OpenPIC  ",
-	NULL,
-	NULL,
-	NULL,
-	chrp_unmask_irq,
-	chrp_mask_irq,
-	chrp_mask_and_ack_irq,
-	0
-};
-#else
-static struct hw_interrupt_type ppc8xx_pic = {
-	" 8xx SIU  ",
-	NULL,
-	NULL,
-	NULL,
-	mbx_unmask_irq,
-	mbx_mask_irq,
-	mbx_mask_and_ack,
-	0
-};
-#endif /* CONFIG_8xx */
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
X 
X int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
X 	unsigned long irqflags, const char * devname, void *dev_id)
@@ -357,19 +233,17 @@
X 	}
X #ifdef __SMP__
X 	/* should this be per processor send/receive? */
-	len += sprintf(buf+len, "IPI: %10lu", ipi_count);
-	for ( i = 0 ; i <= smp_num_cpus-1; i++ )
-		len += sprintf(buf+len,"          ");
-	len += sprintf(buf+len, "     interprocessor messages received\n");
+	len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
X #endif		
-	len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
-	for ( i = 0 ; i <= smp_num_cpus-1; i++ )
-		len += sprintf(buf+len,"        ");
-	len += sprintf(buf+len, "         spurious or short\n");
+	len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
X 	return len;
X }
X 
-static void dispatch_handler(struct pt_regs *regs, int irq)
+/*
+ * Eventually, this should take an array of interrupts and an array size
+ * so it can dispatch multiple interrupts.
+ */
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
X {
X 	int status;
X 	struct irqaction *action;
@@ -390,209 +264,18 @@
X 		__cli();
X 		unmask_irq(irq);
X 	} else {
-		spurious_interrupts++;
+		ppc_spurious_interrupts++;
X 		disable_irq( irq );
X 	}
X }
X 
-#define MAXCOUNT 100000000
X asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
X {
-	int irq;
-	unsigned long bits = 0;
X 	int cpu = smp_processor_id();
-	int openpic_eoi_done = 0;
-
-	hardirq_enter(cpu);
-#ifndef CONFIG_8xx		  
-#ifdef __SMP__
-	/* IPI's are a hack on the powersurge -- Cort */
-	if ( (_machine == _MACH_Pmac) && (cpu != 0) )
-	{
-		if (!isfake)
-		{
-#ifdef CONFIG_XMON
-			static int xmon_2nd;
-			if (xmon_2nd)
-				xmon(regs);
-#endif
-			smp_message_recv();
-			goto out;
-		}
-		/* could be here due to a do_fake_interrupt call but we don't
-		   mess with the controller from the second cpu -- Cort */
-		goto out;
-	}
-
-	{
-		unsigned int loops = MAXCOUNT;
-		while (test_bit(0, &global_irq_lock)) {
-			if (smp_processor_id() == global_irq_holder) {
-				printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
-				xmon(0);
-#endif
-				break;
-			}
-			if (loops-- == 0) {
-				printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
-				xmon(0);
-#endif
-			}
-		}
-	}
-#endif /* __SMP__ */			
-
-	switch ( _machine )
-	{
-	case _MACH_Pmac:
-		for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
-			int i = irq >> 5;
-			bits = ld_le32(&pmac_irq_hw[i]->flag)
-				| lost_interrupts[i];
-			if (bits == 0)
-				continue;
-			irq -= cntlzw(bits);
-			break;
-		}
-		break;
-	case _MACH_chrp:
-		irq = openpic_irq(0);
-		if (irq == IRQ_8259_CASCADE)
-		{
-			/*
-			 * This magic address generates a PCI IACK cycle.
-			 * 
-			 * This should go in the above mask/ack code soon. -- Cort
-			 */
-			irq = *chrp_int_ack_special;
-			/*
-			 * Acknowledge as soon as possible to allow i8259
-			 * interrupt nesting
-			 */
-			openpic_eoi(0);
-			openpic_eoi_done = 1;
-		}
-		if (irq == OPENPIC_VEC_SPURIOUS)
-		{
-				/*
-				 * Spurious interrupts should never be
-				 * acknowledged
-				 */
-			spurious_interrupts++;
-			openpic_eoi_done = 1;
-		}
-		bits = 1UL << irq;
-		break;
-	case _MACH_prep:
-		outb(0x0C, 0x20);
-		irq = inb(0x20) & 7;
-		if (irq == 2)
-		{
-			outb(0x0C, 0xA0);
-			irq = (inb(0xA0) & 7) + 8;
-			bits |= 1UL << irq;
-#if 0			
-			/* It's possible to loose intrs here
-			 * if we get 2 intrs in the upper 8
-			 * bits.  We eoi irq 2 and handle one of
-			 * the upper intrs but then ignore it
-			 * since we've already eoi-d 2.  So,
-			 * we must keep track of lost intrs.
-			 * -- Cort
-			 */
-			while (1)
-			{
-				int i;
-				outb(0x0C, 0xA0);
-				i = inb(0xA0);
-				if ( !(i & 128) )
-					break;
-				irq &= 7;
-				irq += 8;
-				bits |= 1UL << irq;
-			}
-#endif			
-		}
-		else
-			bits = 1UL << irq;
-		  
-		break;
-#ifdef CONFIG_APUS
-	case _MACH_apus:
-	{
-		int old_level, new_level;
-
-		old_level = ~(regs->mq) & IPLEMU_IPLMASK;
-		new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-		
-		if (new_level == 0)
-		{
-			goto apus_out;
-		}
-		
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-		APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-					  | (~(new_level) & IPLEMU_IPLMASK)));
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-		
-		process_int (VEC_SPUR+new_level, regs);
-		
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-		APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-					  | (~(old_level) & IPLEMU_IPLMASK)));
-apus_out:
-		hardirq_exit(cpu);
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-		goto out2;
-	}
-#endif	
-	}
X 
-	if (irq < 0)
-	{
-		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-		       irq, regs->nip);
-		spurious_interrupts++;
-		goto out;
-	}					
-	
-#else /* CONFIG_8xx */
-	/* For MPC8xx, read the SIVEC register and shift the bits down
-	 * to get the irq number.
-	 */
-	bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-	irq = bits >> 26;
-	irq += ppc8xx_pic.irq_offset;
-	bits = 1UL << irq;
-#endif /* CONFIG_8xx */
-#if 0
-	/*
-	 * this allows for > 1 interrupt at a time so we can
-	 * clear out any 'double' interrupts on prep and
-	 * finish up the lost interrupts.
-	 * It doesn't currently work for irqs > 31 so I'm leaving
-	 * it commented out for now.
-	 * -- Cort
-	 */
-	for ( i = 0 ; i < sizeof(bits)*8 ; i++ )
-		if ( bits & (1UL<<i) )
-			dispatch_handler( regs, i );
-#else	
-	dispatch_handler( regs, irq );
-#endif	
-	
-#ifndef CONFIG_8xx
-out:
-	if (_machine == _MACH_chrp && !openpic_eoi_done)
-		openpic_eoi(0);
-#endif /* CONFIG_8xx */
-	hardirq_exit(cpu);
-#ifdef CONFIG_APUS
-out2:
-#endif
+        hardirq_enter(cpu);
+        ppc_md.do_IRQ(regs, cpu, isfake);
+        hardirq_exit(cpu);
X }
X 
X unsigned long probe_irq_on (void)
@@ -605,461 +288,16 @@
X 	return 0;
X }
X 
-static void i8259_mask_and_ack_irq(unsigned int irq_nr)
-{
-	if ( irq_nr >= i8259_pic.irq_offset )	
-		irq_nr -= i8259_pic.irq_offset;
-	if (irq_nr > 7) {
-		cached_A1 |= 1 << (irq_nr-8);
-		inb(0xA1);	/* DUMMY */
-		outb(cached_A1,0xA1);
-		outb(0x62,0x20);	/* Specific EOI to cascade */
-		/*outb(0x20,0xA0);*/
-		outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
-	} else {
-		cached_21 |= 1 << irq_nr;
-		inb(0x21);	/* DUMMY */
-		outb(cached_21,0x21);
-		/*outb(0x20,0x20);*/
-		outb(0x60|irq_nr,0x20); /* specific eoi */
-	}
-}
-
-static void i8259_set_irq_mask(int irq_nr)
-{
-	outb(cached_A1,0xA1);
-	outb(cached_21,0x21);
-}
-
-static void i8259_mask_irq(unsigned int irq_nr)
-{
-	if ( irq_nr >= i8259_pic.irq_offset )	
-		irq_nr -= i8259_pic.irq_offset;
-	if ( irq_nr < 8 )
-		cached_21 |= 1 << irq_nr;
-	else
-		cached_A1 |= 1 << (irq_nr-8);
-	i8259_set_irq_mask(irq_nr);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
-  
-	if ( irq_nr >= i8259_pic.irq_offset )	
-		irq_nr -= i8259_pic.irq_offset;
-	if ( irq_nr < 8 )
-		cached_21 &= ~(1 << irq_nr);
-	else
-		cached_A1 &= ~(1 << (irq_nr-8));
-	i8259_set_irq_mask(irq_nr);
-}
-
-#ifndef CONFIG_8xx
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int irq, bits;
-	
-	for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
-		int i = irq >> 5;
-		bits = ld_le32(&pmac_irq_hw[i]->flag)
-			| lost_interrupts[i];
-		if (bits == 0)
-			continue;
-		irq -= cntlzw(bits);
-		break;
-	}
-	/* The previous version of this code allowed for this case, we
-	 * don't.  Put this here to check for it.
-	 * -- Cort
-	 */
-	if ( irq_desc[irq].ctl != &gatwick_pic )
-		printk("gatwick irq not from gatwick pic\n");
-	else
-		dispatch_handler( regs, irq );
-}
-
-void pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-        clear_bit(irq_nr, cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, lost_interrupts))
-                atomic_dec(&n_lost_interrupts);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        do {
-                /* make sure ack gets to controller before we enable interrupts */
-		mb();
-        } while(in_le32(&pmac_irq_hw[i]->flag) & bit);
-
-}
-
-void __openfirmware chrp_mask_and_ack_irq(unsigned int irq_nr)
-{
-	if (is_8259_irq(irq_nr))
-	    i8259_mask_and_ack_irq(irq_nr);
-}
-
-static void pmac_set_irq_mask(int irq_nr)
-{
-	unsigned long bit = 1UL << (irq_nr & 0x1f);
-	int i = irq_nr >> 5;
-
-	if ((unsigned)irq_nr >= max_irqs)
-		return;
-
-	/* enable unmasked interrupts */
-	out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-	
-	do {
-		/* make sure mask gets to controller before we
-		   return to user */
-		mb();
-	} while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-		!= (cached_irq_mask[i] & bit));
-
-	/*
-	 * Unfortunately, setting the bit in the enable register
-	 * when the device interrupt is already on *doesn't* set
-	 * the bit in the flag register or request another interrupt.
-	 */
-	if ((bit & cached_irq_mask[i])
-	    && (ld_le32(&pmac_irq_hw[i]->level) & bit)
-	    && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
-		if (!test_and_set_bit(irq_nr, lost_interrupts))
-			atomic_inc(&n_lost_interrupts);
-	}
-}
-
-static void pmac_mask_irq(unsigned int irq_nr)
-{
-	clear_bit(irq_nr, cached_irq_mask);
-	pmac_set_irq_mask(irq_nr);
-	mb();
-}
-
-static void pmac_unmask_irq(unsigned int irq_nr)
-{
-	set_bit(irq_nr, cached_irq_mask);
-	pmac_set_irq_mask(irq_nr);
-}
-
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
-{
-	if (is_8259_irq(irq_nr))
-		i8259_mask_irq(irq_nr);
-	else
-		openpic_disable_irq(irq_to_openpic(irq_nr));
-}
-
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
-{
-	if (is_8259_irq(irq_nr))
-		i8259_unmask_irq(irq_nr);
-	else
-		openpic_enable_irq(irq_to_openpic(irq_nr));
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
-	struct device_node *node;
-	int count;
-	
-	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-	node = gw->child;
-	count = 0;
-	while(node)
-	{
-		/* Fix SCC */
-		if (strcasecmp(node->name, "escc") == 0)
-			if (node->child) {
-				if (node->child->n_intrs < 3) {
-					node->child->intrs = &gatwick_int_pool[count];
-					count += 3;
-				}
-				node->child->n_intrs = 3;				
-				node->child->intrs[0].line = 15+irq_base;
-				node->child->intrs[1].line =  4+irq_base;
-				node->child->intrs[2].line =  5+irq_base;
-				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-					node->child->intrs[0].line,
-					node->child->intrs[1].line,
-					node->child->intrs[2].line);
-			}
-		/* Fix media-bay & left SWIM */
-		if (strcasecmp(node->name, "media-bay") == 0) {
-			struct device_node* ya_node;
-
-			if (node->n_intrs == 0)
-				node->intrs = &gatwick_int_pool[count++];
-			node->n_intrs = 1;
-			node->intrs[0].line = 29+irq_base;
-			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-					node->intrs[0].line);
-			
-			ya_node = node->child;
-			while(ya_node)
-			{
-				if (strcasecmp(ya_node->name, "floppy") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 19+irq_base;
-					ya_node->intrs[1].line =  1+irq_base;
-					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				if (strcasecmp(ya_node->name, "ata4") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 14+irq_base;
-					ya_node->intrs[1].line =  3+irq_base;
-					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				ya_node = ya_node->sibling;
-			}
-		}
-		node = node->sibling;
-	}
-	if (count > 10) {
-		printk("WARNING !! Gatwick interrupt pool overflow\n");
-		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
-		printk("              requested = %d\n", count);
-	}
-}
-
-#ifdef __SMP__
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	smp_message_recv();
-}
-#endif /* __SMP__ */
-
-
-#else /* CONFIG_8xx */
-
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int bits, irq;
-
-	/* A bug in the QSpan chip causes it to give us 0xff always
-	 * when doing a character read.  So read 32 bits and shift.
-	 * This doesn't seem to return useful values anyway, but
-	 * read it to make sure things are acked.
-	 * -- Cort
-	 */
-	irq = (inl(0x508) >> 24)&0xff;
-	if ( irq != 0xff ) printk("iack %d\n", irq);
-	
-	outb(0x0C, 0x20);
-	irq = inb(0x20) & 7;
-	if (irq == 2)
-	{
-		outb(0x0C, 0xA0);
-		irq = inb(0xA0);
-		irq = (irq&7) + 8;
-	}
-	bits = 1UL << irq;
-	irq += i8259_pic.irq_offset;
-	dispatch_handler( regs, irq );
-}
-
-static void mbx_mask_and_ack(unsigned int irq_nr)
-{
-	/* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
-	if ( irq_nr != ISA_BRIDGE_INT )
-		mbx_mask_irq(irq_nr);
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	/* clear the pending bits */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
-}
-
-static void mbx_mask_irq(unsigned int irq_nr)
-{
-	if ( irq_nr == ISA_BRIDGE_INT ) return;
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	cached_irq_mask[0] &= ~(1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	cached_irq_mask[0];
-}
-
-static void mbx_unmask_irq(unsigned int irq_nr)
-{
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	cached_irq_mask[0] |= (1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	cached_irq_mask[0];
-}
-#endif /* CONFIG_8xx */
-
-static void __init i8259_init(void)
-{
-	/* init master interrupt controller */
-	outb(0x11, 0x20); /* Start init sequence */
-	outb(0x00, 0x21); /* Vector base */
-	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-	outb(0x01, 0x21); /* Select 8086 mode */
-	outb(0xFF, 0x21); /* Mask all */
-	/* init slave interrupt controller */
-	outb(0x11, 0xA0); /* Start init sequence */
-	outb(0x08, 0xA1); /* Vector base */
-	outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-	outb(0x01, 0xA1); /* Select 8086 mode */
-	outb(0xFF, 0xA1); /* Mask all */
-	outb(cached_A1, 0xA1);
-	outb(cached_21, 0x21);
-	request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
-		     "8259 secondary cascade", NULL );
-	enable_irq(i8259_pic.irq_offset + 2);  /* Enable cascade interrupt */
-}
-
X void __init init_IRQ(void)
X {
-	extern void xmon_irq(int, void *, struct pt_regs *);
-	int i;
X 	static int once = 0;
-#ifndef CONFIG_8xx
-	struct device_node *irqctrler;
-	unsigned long addr;
-	struct device_node *np;
-	int second_irq = -999;
-#endif
+
X 	if ( once )
X 		return;
X 	else
X 		once++;
X 	
-#ifndef CONFIG_8xx
-	switch (_machine)
-	{
-	case _MACH_Pmac:
-		/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
-		   others have 32 */
-		max_irqs = max_real_irqs = 32;
-		irqctrler = find_devices("mac-io");
-		if (irqctrler)
-		{
-			max_real_irqs = 64;
-			if (irqctrler->next)
-				max_irqs = 128;
-			else
-				max_irqs = 64;
-		}
-		for ( i = 0; i < max_real_irqs ; i++ )
-			irq_desc[i].ctl = &pmac_pic;
-
-		/* get addresses of first controller */
-		if (irqctrler) {
-			if  (irqctrler->n_addrs > 0) {
-				addr = (unsigned long) 
-					ioremap(irqctrler->addrs[0].address, 0x40);
-				for (i = 0; i < 2; ++i)
-					pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-						(addr + (2 - i) * 0x10);
-			}
-			
-			/* get addresses of second controller */
-			irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
-			if (irqctrler && irqctrler->n_addrs > 0) {
-				addr = (unsigned long) 
-					ioremap(irqctrler->addrs[0].address, 0x40);
-				for (i = 2; i < 4; ++i)
-					pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-						(addr + (4 - i) * 0x10);
-			}
-		}
-
-		/* disable all interrupts in all controllers */
-		for (i = 0; i * 32 < max_irqs; ++i)
-			out_le32(&pmac_irq_hw[i]->enable, 0);
-		
-		/* get interrupt line of secondary interrupt controller */
-		if (irqctrler) {
-			second_irq = irqctrler->intrs[0].line;
-			printk(KERN_INFO "irq: secondary controller on irq %d\n",
-				(int)second_irq);
-			if (device_is_compatible(irqctrler, "gatwick"))
-				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-			for ( i = max_real_irqs ; i < max_irqs ; i++ )
-				irq_desc[i].ctl = &gatwick_pic;
-			request_irq( second_irq, gatwick_action, SA_INTERRUPT,
-				     "gatwick cascade", 0 );
-		}
-		printk("System has %d possible interrupts\n", max_irqs);
-		if (max_irqs != max_real_irqs)
-			printk(KERN_DEBUG "%d interrupts on main controller\n",
-				max_real_irqs);
-
-#ifdef CONFIG_XMON
-		request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
-#endif	/* CONFIG_XMON */
-		break;
-	case _MACH_chrp:
-		if ( !(np = find_devices("pci") ) )
-			printk("Cannot find pci to get ack address\n");
-		else
-		{
-			chrp_int_ack_special = (volatile unsigned char *)
-				(*(unsigned long *)get_property(np,
-					"8259-interrupt-acknowledge", NULL));
-		}
-		for ( i = 16 ; i < 36 ; i++ )
-			irq_desc[i].ctl = &open_pic;
-		/* openpic knows that it's at irq 16 offset
-		 * so we don't need to set it in the pic structure
-		 * -- Cort
-		 */
-		openpic_init(1);
-		for ( i = 0 ; i < 16  ; i++ )
-			irq_desc[i].ctl = &i8259_pic;
-		i8259_init();
-#ifdef CONFIG_XMON
-		request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
-			    xmon_irq, 0, "NMI", 0);
-#endif	/* CONFIG_XMON */
-#ifdef __SMP__
-		request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS),
-			    openpic_ipi_action, 0, "IPI0", 0);
-#endif	/* __SMP__ */
-		break;
-	case _MACH_prep:
-		for ( i = 0 ; i < 16  ; i++ )
-			irq_desc[i].ctl = &i8259_pic;
-		i8259_init();
-		break;
-#ifdef CONFIG_APUS		
-	case _MACH_apus:
-		apus_init_IRQ();
-		break;
-#endif	
-	}
-#else /* CONFIG_8xx */
-	ppc8xx_pic.irq_offset = 16;
-	for ( i = 16 ; i < 32 ; i++ )
-		irq_desc[i].ctl = &ppc8xx_pic;
-	unmask_irq(CPM_INTERRUPT);
-
-	for ( i = 0 ; i < 16 ; i++ )
-		irq_desc[i].ctl = &i8259_pic;
-	i8259_init();
-	request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
-	enable_irq(ISA_BRIDGE_INT);
-#endif  /* CONFIG_8xx */
+	ppc_md.init_IRQ();
X }
X 
X #ifdef __SMP__
@@ -1078,9 +316,13 @@
X 
X 	printk("\n%s, CPU %d:\n", str, cpu);
X 	printk("irq:  %d [%d %d]\n",
-		atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
+	       atomic_read(&global_irq_count),
+	       ppc_local_irq_count[0],
+	       ppc_local_irq_count[1]);
X 	printk("bh:   %d [%d %d]\n",
-		atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
+	       atomic_read(&global_bh_count),
+	       ppc_local_bh_count[0],
+	       ppc_local_bh_count[1]);
X 	stack = (unsigned long *) &str;
X 	for (i = 40; i ; i--) {
X 		unsigned long x = *++stack;
@@ -1115,7 +357,8 @@
X 		 * already executing in one..
X 		 */
X 		if (!atomic_read(&global_irq_count)) {
-			if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+			if (ppc_local_bh_count[cpu]
+			    || !atomic_read(&global_bh_count))
X 				break;
X 		}
X 
@@ -1136,7 +379,8 @@
X 				continue;
X 			if (global_irq_lock)
X 				continue;
-			if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+			if (!ppc_local_bh_count[cpu]
+			    && atomic_read(&global_bh_count))
X 				continue;
X 			if (!test_and_set_bit(0,&global_irq_lock))
X 				break;
@@ -1226,7 +470,7 @@
X 	if (flags & (1 << 15)) {
X 		int cpu = smp_processor_id();
X 		__cli();
-		if (!local_irq_count[cpu])
+		if (!ppc_local_irq_count[cpu])
X 			get_irqlock(cpu);
X 	}
X }
@@ -1235,7 +479,7 @@
X {
X 	int cpu = smp_processor_id();
X 
-	if (!local_irq_count[cpu])
+	if (!ppc_local_irq_count[cpu])
X 		release_irqlock(cpu);
X 	__sti();
X }
@@ -1259,7 +503,7 @@
X 	retval = 2 + local_enabled;
X 
X 	/* check for global flags if we're not in an interrupt */
-	if (!local_irq_count[smp_processor_id()]) {
+	if (!ppc_local_irq_count[smp_processor_id()]) {
X 		if (local_enabled)
X 			retval = 1;
X 		if (global_irq_holder == (unsigned char) smp_processor_id())
@@ -1268,6 +512,31 @@
X 	return retval;
X }
X 
+int
+tb(long vals[],
+   int  max_size)
+{
+   register unsigned long *orig_sp __asm__ ("r1");
+   register unsigned long lr __asm__ ("r3");
+   unsigned long *sp;
+   int i;
+
+   asm volatile ("mflr 3");
+   vals[0] = lr;
+   sp = (unsigned long *) *orig_sp;
+   sp = (unsigned long *) *sp;
+   for (i=1; i<max_size; i++) {
+      if (sp == 0) {
+         break;
+      }
+
+      vals[i] = *(sp+1);
+      sp = (unsigned long *) *sp;
+   }
+
+   return i;
+}
+
X void __global_restore_flags(unsigned long flags)
X {
X 	switch (flags) {
@@ -1284,8 +553,20 @@
X 		__sti();
X 		break;
X 	default:
+	{
+		unsigned long trace[5];
+                int           count;
+                int           i;
+
X 		printk("global_restore_flags: %08lx (%08lx)\n",
X 			flags, (&flags)[-1]);
+                count = tb(trace, 5);
+                printk("tb:");
+                for(i=0; i<count; i++) {
+			printk(" %8.8lx", trace[i]);
+		}
+		printk("\n");
+	}
X 	}
X }
X #endif /* __SMP__ */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h
--- v2.2.7/linux/arch/ppc/kernel/local_irq.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/local_irq.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,45 @@
+
+#ifndef _PPC_KERNEL_LOCAL_IRQ_H
+#define _PPC_KERNEL_LOCAL_IRQ_H
+
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+
+/* Structure describing interrupts */
+struct hw_interrupt_type {
+	const char * typename;
+	void (*startup)(unsigned int irq);
+	void (*shutdown)(unsigned int irq);
+	void (*handle)(unsigned int irq, struct pt_regs * regs);
+	void (*enable)(unsigned int irq);
+	void (*disable)(unsigned int irq);
+	void (*mask_and_ack)(unsigned int irq);
+	int irq_offset;
+};
+
+#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
+#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
+
+struct irqdesc {
+	struct irqaction *action;
+	struct hw_interrupt_type *ctl;
+};
+
+extern struct irqdesc irq_desc[NR_IRQS];
+
+
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
+
+extern int ppc_spurious_interrupts;
+extern int ppc_second_irq;
+extern struct irqaction *ppc_irq_action[NR_IRQS];
+extern unsigned int ppc_local_bh_count[NR_CPUS];
+extern unsigned int ppc_local_irq_count[NR_CPUS];
+extern unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+extern atomic_t ppc_n_lost_interrupts;
+
+#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/mbx_pci.c linux/arch/ppc/kernel/mbx_pci.c
--- v2.2.7/linux/arch/ppc/kernel/mbx_pci.c	Thu Apr 23 20:21:29 1998
+++ linux/arch/ppc/kernel/mbx_pci.c	Thu Apr 29 12:39:01 1999
@@ -252,3 +252,20 @@
X     }
X     return PCIBIOS_DEVICE_NOT_FOUND;
X }
+
+__initfunc(
+void
+mbx_pcibios_fixup(void))
+{
+   /* Nothing to do here? */
+}
+
+__initfunc(
+void
+mbx_setup_pci_ptrs(void))
+{
+	set_config_access_method(mbx);
+
+	ppc_md.pcibios_fixup = mbx_pcibios_fixup;
+}
+
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- v2.2.7/linux/arch/ppc/kernel/mbx_setup.c	Fri Jan  8 22:36:02 1999
+++ linux/arch/ppc/kernel/mbx_setup.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $
+ * $Id: mbx_setup.c,v 1.9 1999/04/28 11:54:09 davem Exp $
X  *
X  *  linux/arch/ppc/kernel/setup.c
X  *
@@ -39,6 +39,22 @@
X #include <asm/pgtable.h>
X #include <asm/ide.h>
X #include <asm/mbx.h>
+#include <asm/machdep.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+static int mbx_set_rtc_time(unsigned long time);
+unsigned long mbx_get_rtc_time(void);
+void mbx_calibrate_decr(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
X 
X extern unsigned long loops_per_sec;
X 
@@ -55,35 +71,10 @@
X extern unsigned long find_available_memory(void);
X extern void m8xx_cpm_reset(uint);
X 
-/* this really does make things cleaner -- Cort */
-void __init powermac_init(void)
-{
-}
-
X void __init adbdev_init(void)
X {
X }
X 
-void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
-	ide_ioreg_t port = base;
-	int i = 8;
-
-	while (i--)
-		*p++ = port++;
- *p++ = base + 0x206;
-	if (irq != NULL)
-		*irq = 0;
-#ifdef ATA_FLASH
-	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
-	for (i = 0; i < 8; ++i)
-		*p++ = base++;
-	*p = ++base;		/* Does not matter */
-	if (irq)
-		*irq = 13;
-#endif
-}
-
X __initfunc(void
X mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
X {
@@ -144,4 +135,338 @@
X 	xmon(0);
X #endif
X 	machine_restart(NULL);
+}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four.  Currently, we only
+ * support the MBX, which is system clock divided by sixteen.
+ */
+__initfunc(void mbx_calibrate_decr(void))
+{
+	bd_t	*binfo = (bd_t *)&res;
+	int freq, fp, divisor;
+
+	if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+		printk("WARNING: Wrong decrementer source clock.\n");
+
+	/* The manual says the frequency is in Hz, but it is really
+	 * as MHz.  The value 'fp' is the number of decrementer ticks
+	 * per second.
+	 */
+	fp = (binfo->bi_intfreq * 1000000) / 16;
+	freq = fp*60;	/* try to make freq/1e6 an integer */
+        divisor = 60;
+        printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+        decrementer_count = freq / HZ / divisor;
+        count_period_num = divisor;
+        count_period_den = freq / 1000000;
+}
+
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	printk("timebase_interrupt()\n");
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+mbx_set_rtc_time(unsigned long time)
+{
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+	((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+	return(0);
+}
+
+initfunc(unsigned long
+mbx_get_rtc_time(void)
+{
+	/* First, unlock all of the registers we are going to modify.
+	 * To protect them from corruption during power down, registers
+	 * that are maintained by keep alive power are "locked".  To
+	 * modify these registers we have to write the key value to
+	 * the key location associated with the register.
+	 */
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+
+
+	/* Disable the RTC one second and alarm interrupts.
+	*/
+	((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+						~(RTCSC_SIE | RTCSC_ALE);
+
+	/* Enabling the decrementer also enables the timebase interrupts
+	 * (or from the other point of view, to get decrementer interrupts
+	 * we have to enable the timebase).  The decrementer interrupt
+	 * is wired into the vector table, nothing to do here for that.
+	 */
+	((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+					 (TBSCR_TBF | TBSCR_TBE));
+	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+
+	/* Get time from the RTC.
+	*/
+	return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
+}
+
+void
+mbx_restart(char *cmd)
+{
+	extern void MBX_gorom(void);
+
+	MBX_gorom();
+}
+
+void
+mbx_power_off(void)
+{
+   mbx_restart(NULL);
+}
+
+void
+mbx_halt(void)
+{
+   mbx_restart(NULL)
+}
+
+
+int mbx_setup_residual(char *buffer)
+{
+        int     len = 0;
+	bd_t	*bp;
+	extern	RESIDUAL *res;
+			
+	bp = (bd_t *)res;
+			
+	len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
+		       "bus clock\t: %dMHz\n",
+		       bp->bi_intfreq /*/ 1000000*/,
+		       bp->bi_busfreq /*/ 1000000*/);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 09'
echo 'File patch-2.2.8 is continued in part 10'
echo 10 > _shar_seq_.tmp
#!/bin/sh
# this is part 10 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 10; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+
+	return len;
+}
+
+void
+mbx_do_IRQ(struct pt_regs *regs,
+	   int            cpu,
+           int            isfake)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+        irq += ppc8xx_pic.irq_offset;
+        bits = 1UL << irq;
+
+	if (irq < 0) {
+		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+		       irq, regs->nip);
+		spurious_interrupts++;
+	}
+	else {
+                ppc_irq_dispatch_handler( regs, irq );
+	}
+
+}
+
+static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int bits, irq;
+
+	/* A bug in the QSpan chip causes it to give us 0xff always
+	 * when doing a character read.  So read 32 bits and shift.
+	 * This doesn't seem to return useful values anyway, but
+	 * read it to make sure things are acked.
+	 * -- Cort
+	 */
+	irq = (inl(0x508) >> 24)&0xff;
+	if ( irq != 0xff ) printk("iack %d\n", irq);
+	
+	outb(0x0C, 0x20);
+	irq = inb(0x20) & 7;
+	if (irq == 2)
+	{
+		outb(0x0C, 0xA0);
+		irq = inb(0xA0);
+		irq = (irq&7) + 8;
+	}
+	bits = 1UL << irq;
+ irq += i8259_pic.irq_offset;
+	ppc_irq_dispatch_handler( regs, irq );
+}
+
+
+/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug.  External
+ * interrupts can be either edge or level triggered, but there is no
+ * reason for us to change the EPPC-bug values (it would not work if we did).
+ */
+__initfunc(void
+mbx_init_IRQ(void))
+{
+	int i;
+
+        ppc8xx_pic.irq_offset = 16;
+        for ( i = 16 ; i < 32 ; i++ )
+                irq_desc[i].ctl = &ppc8xx_pic;
+        unmask_irq(CPM_INTERRUPT);
+
+        for ( i = 0 ; i < 16 ; i++ )
+                irq_desc[i].ctl = &i8259_pic;
+        i8259_init();
+        request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
+        enable_irq(ISA_BRIDGE_INT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+mbx_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port+_IO_BASE), buf, ns);
+}
+
+void
+mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+mbx_ide_default_irq(ide_ioreg_t base)
+{
+        return 14;
+}
+
+ide_ioreg_t
+mbx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+int
+mbx_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return 0
+}
+
+void
+mbx_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+}
+
+void
+mbx_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+}
+
+void
+mbx_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+	ide_ioreg_t port = base;
+	int i = 8;
+
+	while (i--)
+		*p++ = port++;
+ *p++ = base + 0x206;
+	if (irq != NULL)
+		*irq = 0;
+#ifdef ATA_FLASH
+	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+	for (i = 0; i < 8; ++i)
+		*p++ = base++;
+	*p = ++base;		/* Does not matter */
+	if (irq)
+		*irq = 13;
+#endif
+}
+#endif
+
+__initfunc(void
+mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	 unsigned long r6, unsigned long r7))
+{
+
+	if ( r3 )
+		memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+	
+#ifdef CONFIG_PCI
+	mbx_setup_pci_ptrs();
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+	/* take care of cmd line */
+	if ( r6 )
+	{
+		
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch     = mbx_setup_arch;
+	ppc_md.setup_residual = mbx_setup_residual;
+	ppc_md.get_cpuinfo    = NULL;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = mbx_init_IRQ;
+	ppc_md.do_IRQ         = mbx_do_IRQ;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = mbx_restart;
+	ppc_md.power_off      = mbx_power_off;
+	ppc_md.halt           = mbx_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = mbx_set_rtc_time;
+	ppc_md.get_rtc_time   = mbx_get_rtc_time;
+	ppc_md.calibrate_decr = mbx_calibrate_decr;
+
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = mbx_ide_insw;
+        ppc_ide_md.outsw = mbx_ide_outsw;
+        ppc_ide_md.default_irq = mbx_ide_default_irq;
+        ppc_ide_md.default_io_base = mbx_ide_default_io_base;
+        ppc_ide_md.check_region = mbx_ide_check_region;
+        ppc_ide_md.request_region = mbx_ide_request_region;
+        ppc_ide_md.release_region = mbx_ide_release_region;
+        ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
X }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.2.7/linux/arch/ppc/kernel/misc.S	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/misc.S	Thu Apr 29 12:39:01 1999
@@ -36,6 +36,7 @@
X  * Returns (address we're running at) - (address we were linked at)
X  * for use before the text and data are mapped to KERNELBASE.
X  */
+
X _GLOBAL(reloc_offset)
X 	mflr	r0
X 	bl	1f
@@ -72,8 +73,8 @@
X 	beqlr			/* nothing to do if state == 0 */
X _GLOBAL(__sti)
X _GLOBAL(_hard_sti)
-	lis	r4,n_lost_interrupts@ha
-	lwz	r4,n_lost_interrupts@l(r4)
+	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
X 	mfmsr	r3		/* Get current state */
X 	ori	r3,r3,MSR_EE	/* Turn on 'EE' bit */
X 	cmpi	0,r4,0		/* lost interrupts to process first? */
@@ -93,8 +94,8 @@
X 	stw	r0,20(r1)
X 	stw	r3,8(r1)
X 1:	bl	fake_interrupt
-	lis	r4,n_lost_interrupts@ha
-	lwz	r4,n_lost_interrupts@l(r4)
+	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
X 	cmpi	0,r4,0
X 	bne-	1b
X 	lwz	r3,8(r1)
@@ -105,6 +106,20 @@
X 	addi	r1,r1,16
X 	blr
X 
+
+/*
+ * complement mask on the msr then "or" some values on.
+ *     _nmask_and_or_msr(nmask, value_to_or)
+ */
+	_GLOBAL(_nmask_and_or_msr)
+	mfmsr	r0		/* Get current msr */
+	andc	r0,r0,r3	/* And off the bits set in r3 (first parm) */
+	or	r0,r0,r4		/* Or on the bits in r4 (second parm) */
+	sync			/* Some chip revs have problems here... */
+	mtmsr	r0		/* Update machine state */
+	blr			/* Done */
+
+
X /*
X  * Flush MMU TLB
X  */
@@ -613,16 +628,6 @@
X 	stfd	0,-4(r5)
X 	blr
X 
-        .globl  __clear_msr_me
-__clear_msr_me:
-        mfmsr   r0                      /* Get current interrupt state */
-        lis     r3,0
-        ori     r3,r3,MSR_ME
-        andc    r0,r0,r3                /* Clears bit in (r4) */
-        sync                            /* Some chip revs have problems here */
-        mtmsr   r0                      /* Update machine state */
-        blr
-
X _GLOBAL(cvt_df)
X cvt_df:
X 	lfd	0,-4(r5)	/* load up fpscr value */
@@ -633,6 +638,16 @@
X 	stfd	0,-4(r5)
X 	blr
X 
+        .globl  __clear_msr_me
+__clear_msr_me:
+        mfmsr   r0                      /* Get current interrupt state */
+        lis     r3,0
+        ori     r3,r3,MSR_ME
+        andc    r0,r0,r3                /* Clears bit in (r4) */
+        sync                            /* Some chip revs have problems here */
+        mtmsr   r0                      /* Update machine state */
+        blr
+
X /*
X  * Fetch the current SR register
X  *   get_SR(int index)
@@ -651,6 +666,8 @@
X 	sc
X 	cmpi	0,r3,0		/* parent or child? */
X 	bnelr			/* return if parent */
+	li	r0,0		/* clear out p->tss.regs */
+	stw	r0,TSS+PT_REGS(r2)	/* since we don't have user ctx */
X 	mtlr	r4              /* fn addr in lr */
X 	mr	r3,r5	        /* load arg and call fn */
X 	blrl
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.2.7/linux/arch/ppc/kernel/mk_defs.c	Wed Sep  9 14:51:06 1998
+++ linux/arch/ppc/kernel/mk_defs.c	Tue May 11 08:24:32 1999
@@ -29,7 +29,7 @@
X int
X main(void)
X {
-	DEFINE(KERNELBASE, KERNELBASE);
+	/*DEFINE(KERNELBASE, KERNELBASE);*/
X 	DEFINE(STATE, offsetof(struct task_struct, state));
X 	DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
X 	DEFINE(COUNTER, offsetof(struct task_struct, counter));
@@ -48,7 +48,6 @@
X 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
X 	DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
X 	DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
-	DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
X 	/* Interrupt register frame */
X 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
X 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.2.7/linux/arch/ppc/kernel/open_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/open_pic.c	Tue May 11 08:24:32 1999
@@ -0,0 +1,48 @@
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/openpic.h>
+#include <asm/irq.h>
+#include "open_pic.h"
+#include "i8259.h"
+
+#ifdef __SMP__
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	smp_message_recv();
+}
+#endif /* __SMP__ */
+
+void chrp_mask_and_ack_irq(unsigned int irq_nr)
+{
+	if (is_8259_irq(irq_nr))
+	    i8259_pic.mask_and_ack(irq_nr);
+}
+
+static void chrp_mask_irq(unsigned int irq_nr)
+{
+	if (is_8259_irq(irq_nr))
+		i8259_pic.disable(irq_nr);
+	else
+		openpic_disable_irq(irq_to_openpic(irq_nr));
+}
+
+static void chrp_unmask_irq(unsigned int irq_nr)
+{
+	if (is_8259_irq(irq_nr))
+		i8259_pic.enable(irq_nr);
+	else
+		openpic_enable_irq(irq_to_openpic(irq_nr));
+}
+
+struct hw_interrupt_type open_pic = {
+	" OpenPIC  ",
+	NULL,
+	NULL,
+	NULL,
+	chrp_unmask_irq,
+	chrp_mask_irq,
+	chrp_mask_and_ack_irq,
+	0
+};
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h
--- v2.2.7/linux/arch/ppc/kernel/open_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/open_pic.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,11 @@
+
+#ifndef _PPC_KERNEL_OPEN_PIC_H
+#define _PPC_KERNEL_OPEN_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type open_pic;
+
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c
--- v2.2.7/linux/arch/ppc/kernel/openpic.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/openpic.c	Thu Apr 29 12:39:01 1999
@@ -190,6 +190,9 @@
X 	case 2:
X 	    version = "1.2";
X 	    break;
+	case 3:
+	    version = "1.3";
+	    break;
X 	default:
X 	    version = "?";
X 	    break;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.2.7/linux/arch/ppc/kernel/pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/pci.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: pci.c,v 1.53 1999/03/12 23:38:02 cort Exp $
+ * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $
X  * Common pmac/prep/chrp pci routines. -- Cort
X  */
X 
@@ -21,97 +21,41 @@
X #include <asm/irq.h>
X #include <asm/gg2.h>
X 
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-unsigned int * pci_config_address;
-unsigned char * pci_config_data;
-
-static void fix_intr(struct device_node *node, struct pci_dev *dev);
-
-/*
- * It would be nice if we could create a include/asm/pci.h and have just
- * function ptrs for all these in there, but that isn't the case.
- * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
- * which has been setup by pcibios_init().  This is all to avoid a check
- * for pmac/prep every time we call one of these.  It should also make the move
- * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
- * and create pci.h
- *   -- Cort
- */
-int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
-				    unsigned char offset, unsigned char *val);
-int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
-				    unsigned char offset, unsigned short *val);
-int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned int *val);
-int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned char val);
-int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned short val);
-int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned int val);
-
-#define decl_config_access_method(name) \
-extern int name##_pcibios_read_config_byte(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned char *val); \
-extern int name##_pcibios_read_config_word(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned short *val); \
-extern int name##_pcibios_read_config_dword(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned int *val); \
-extern int name##_pcibios_write_config_byte(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned char val); \
-extern int name##_pcibios_write_config_word(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned short val); \
-extern int name##_pcibios_write_config_dword(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned int val)
-
-#define set_config_access_method(name) \
-	ptr_pcibios_read_config_byte = name##_pcibios_read_config_byte; \
-	ptr_pcibios_read_config_word = name##_pcibios_read_config_word; \
-	ptr_pcibios_read_config_dword = name##_pcibios_read_config_dword; \
-	ptr_pcibios_write_config_byte = name##_pcibios_write_config_byte; \
-	ptr_pcibios_write_config_word = name##_pcibios_write_config_word; \
-	ptr_pcibios_write_config_dword = name##_pcibios_write_config_dword
-
-decl_config_access_method(mech1);
-decl_config_access_method(pmac);
-decl_config_access_method(grackle);
-decl_config_access_method(gg2);
-decl_config_access_method(raven);
-decl_config_access_method(prep);
-decl_config_access_method(mbx);
-decl_config_access_method(python);
+#include "pci.h"
+
+unsigned long isa_io_base     = 0;
+unsigned long isa_mem_base    = 0;
+unsigned long pci_dram_offset = 0;
X 
X int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
X 			     unsigned char offset, unsigned char *val)
X {
-	return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
+	return ppc_md.pcibios_read_config_byte(bus,dev_fn,offset,val);
X }
X int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
X 			     unsigned char offset, unsigned short *val)
X {
-	return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
+	return ppc_md.pcibios_read_config_word(bus,dev_fn,offset,val);
X }
X int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
X 			      unsigned char offset, unsigned int *val)
X {
-	return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
+	return ppc_md.pcibios_read_config_dword(bus,dev_fn,offset,val);
X }
X int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
X 			      unsigned char offset, unsigned char val)
X {
-	return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
+	return ppc_md.pcibios_write_config_byte(bus,dev_fn,offset,val);
X }
X int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
X 			      unsigned char offset, unsigned short val)
X {
-	return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
+	return ppc_md.pcibios_write_config_word(bus,dev_fn,offset,val);
X }
X int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
X 			       unsigned char offset, unsigned int val)
X {
-	return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
+	return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val);
X }
X 
X int pcibios_present(void)
@@ -123,175 +67,10 @@
X {
X }
X 
-void __init setup_pci_ptrs(void)
-{
-#ifndef CONFIG_MBX
-	PPC_DEVICE *hostbridge;
-	switch (_machine) {
-	case _MACH_prep:
-                printk("PReP architecture\n");
-                if ( _prep_type == _PREP_Radstone )
-                {
-                        printk("Setting PCI access method to mech1\n");
-                        set_config_access_method(mech1);
-                        break;
-                }
-
-	  	hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
-						BridgeController, PCIBridge,
-						-1, 0);
-		if (hostbridge && 
-		    hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
-			PnP_TAG_PACKET * pkt;	
-			set_config_access_method(raven);
-			pkt=PnP_find_large_vendor_packet(
-			       res->DevicePnPHeap+hostbridge->AllocatedOffset, 
-			       3, 0);
-			if(pkt) { 
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
-				pci_config_address= (unsigned *)
-				  ld_le32((unsigned *) p.PPCData);
-				pci_config_data= (unsigned char *)
-				  ld_le32((unsigned *) (p.PPCData+8));
-			} else {/* default values */
-				pci_config_address= (unsigned *) 0x80000cf8;
-				pci_config_data= (unsigned char *) 0x80000cfc; 
-			}  
-		} else {
-			set_config_access_method(prep);
-		}
-		break;
-	case _MACH_Pmac:
-		if (find_devices("pci") != 0) {
-			/* looks like a G3 powermac */
-			set_config_access_method(grackle);
-		} else {
-			set_config_access_method(pmac);
-		}
-		break;
-	case _MACH_chrp:
-		if ( !strncmp("MOT",
-			      get_property(find_path_device("/"), "model", NULL),3) )
-		{
-			pci_dram_offset = 0;
-			isa_mem_base = 0xf7000000;
-			isa_io_base = 0xfe000000;
-			set_config_access_method(grackle);
-		}
-		else
-		{
-			if ( !strncmp("F5",
-			      get_property(find_path_device("/"),
-					   "ibm,model-class", NULL),2) )
-		
-			{
-				pci_dram_offset = 0x80000000;
-				isa_mem_base = 0xa0000000;
-				isa_io_base = 0x88000000;
-				set_config_access_method(python);
-			}
-			else
-			{
-				pci_dram_offset = 0;
-				isa_mem_base = 0xf7000000;
-				isa_io_base = 0xf8000000;
-				set_config_access_method(gg2);
-			}
-		}
-		break;
-	default:
-		printk("setup_pci_ptrs(): unknown machine type!\n");
-	}
-#else  /* CONFIG_MBX */
-	set_config_access_method(mbx);
-#endif /* CONFIG_MBX */	
-#undef set_config_access_method
-}
X 
X void __init pcibios_fixup(void)
X {
-	extern unsigned long route_pci_interrupts(void);
-	struct pci_dev *dev;
-	extern struct bridge_data **bridges;
-	extern unsigned char *Motherboard_map;
-	extern unsigned char *Motherboard_routes;
-	unsigned char i;
-#ifndef CONFIG_MBX
-	switch (_machine )
-	{
-	case _MACH_prep:
-                if ( _prep_type == _PREP_Radstone )
-                {
-                        printk("Radstone boards require no PCI fixups\n");
-                        break;
-                }
-
-		route_pci_interrupts();
-		for(dev=pci_devices; dev; dev=dev->next)
-		{
-			/*
-			 * Use our old hard-coded kludge to figure out what
-			 * irq this device uses.  This is necessary on things
-			 * without residual data. -- Cort
-			 */
-			unsigned char d = PCI_SLOT(dev->devfn);
-			dev->irq = Motherboard_routes[Motherboard_map[d]];
-			for ( i = 0 ; i <= 5 ; i++ )
-			{
-				if ( dev->base_address[i] > 0x10000000 )
-				{
-					printk("Relocating PCI address %lx -> %lx\n",
-					       dev->base_address[i],
-					       (dev->base_address[i] & 0x00FFFFFF)
-				               | 0x01000000);
-					dev->base_address[i] =
-					  (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
-					pci_write_config_dword(dev,
-						PCI_BASE_ADDRESS_0+(i*0x4),
-						dev->base_address[i] );
-				}
-			}
-#if 0			
-			/*
-			 * If we have residual data and if it knows about this
-			 * device ask it what the irq is.
-			 *  -- Cort
-			 */
-			ppcd = residual_find_device_id( ~0L, dev->device,
-							-1,-1,-1, 0);
-#endif			
-		}
-		break;
-	case _MACH_chrp:
-		/* PCI interrupts are controlled by the OpenPIC */
-		for(dev=pci_devices; dev; dev=dev->next)
-			if (dev->irq)
-				dev->irq = openpic_to_irq(dev->irq);
-		break;
-	case _MACH_Pmac:
-		for(dev=pci_devices; dev; dev=dev->next)
-		{
-			/*
-			 * Open Firmware often doesn't initialize the,
-			 * PCI_INTERRUPT_LINE config register properly, so we
-			 * should find the device node and se if it has an
-			 * AAPL,interrupts property.
-			 */
-			struct bridge_data *bp = bridges[dev->bus->number];
-			unsigned char pin;
-
-			if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
-			    !pin) 
-				continue;	/* No interrupt generated -> no fixup */
-			fix_intr(bp->node->child, dev);
-		}
-		break;
-	}
-#else /* CONFIG_MBX */
-	for(dev=pci_devices; dev; dev=dev->next)
-	{
-	}
-#endif /* CONFIG_MBX */
+	ppc_md.pcibios_fixup();
X }
X 
X void __init pcibios_fixup_bus(struct pci_bus *bus)
@@ -309,7 +88,7 @@
X  * fix IRQ's for cards located behind P2P bridges.
X  * - Ranjit Deshpande, 01/20/99
X  */
-static void __init fix_intr(struct device_node *node, struct pci_dev *dev)
+void __init fix_intr(struct device_node *node, struct pci_dev *dev)
X {
X 	unsigned int *reg, *class_code;
X 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pci.h linux/arch/ppc/kernel/pci.h
--- v2.2.7/linux/arch/ppc/kernel/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pci.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,36 @@
+
+#ifndef __PPC_KERNEL_PCI_H__
+#define __PPC_KERNEL_PCI_H__
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_dram_offset;
+
+extern unsigned int  *pci_config_address;
+extern unsigned char *pci_config_data;
+
+void fix_intr(struct device_node *node, struct pci_dev *dev);
+
+#define decl_config_access_method(name) \
+extern int name##_pcibios_read_config_byte(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned char *val); \
+extern int name##_pcibios_read_config_word(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned short *val); \
+extern int name##_pcibios_read_config_dword(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned int *val); \
+extern int name##_pcibios_write_config_byte(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned char val); \
+extern int name##_pcibios_write_config_word(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned short val); \
+extern int name##_pcibios_write_config_dword(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned int val)
+
+#define set_config_access_method(name) \
+	ppc_md.pcibios_read_config_byte = name##_pcibios_read_config_byte; \
+	ppc_md.pcibios_read_config_word = name##_pcibios_read_config_word; \
+	ppc_md.pcibios_read_config_dword = name##_pcibios_read_config_dword; \
+	ppc_md.pcibios_write_config_byte = name##_pcibios_write_config_byte; \
+	ppc_md.pcibios_write_config_word = name##_pcibios_write_config_word; \
+	ppc_md.pcibios_write_config_dword = name##_pcibios_write_config_dword
+
+#endif /* __PPC_KERNEL_PCI_H__ */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.2.7/linux/arch/ppc/kernel/pmac_pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/pmac_pci.c	Thu Apr 29 12:39:01 1999
@@ -21,6 +21,9 @@
X #include <asm/pgtable.h>
X #include <asm/prom.h>
X #include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
X 
X struct bridge_data **bridges, *bridge_list;
X static int max_bus;
@@ -437,5 +440,49 @@
X 		if (strcmp(dev->name, "bandit") == 0)
X 			init_bandit(bp);
X 	}
+}
+
+__initfunc(
+void
+pmac_pcibios_fixup(void))
+{
+	struct pci_dev *dev;
+	
+	/*
+	 * FIXME: This is broken: We should not assign IRQ's to IRQless
+	 *	  devices (look at PCI_INTERRUPT_PIN) and we also should
+	 *	  honor the existence of multi-function devices where
+	 *	  different functions have different interrupt pins. [mj]
+	 */
+	for(dev=pci_devices; dev; dev=dev->next)
+	{
+		/*
+		 * Open Firmware often doesn't initialize the,
+		 * PCI_INTERRUPT_LINE config register properly, so we
+		 * should find the device node and se if it has an
+		 * AAPL,interrupts property.
+		 */
+		struct bridge_data *bp = bridges[dev->bus->number];
+		unsigned char pin;
+			
+		if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+		    !pin)
+			continue; /* No interrupt generated -> no fixup */
+                fix_intr(bp->node->child, dev);
+	}
+}
+
+__initfunc(
+void
+pmac_setup_pci_ptrs(void))
+{
+	if (find_devices("pci") != 0) {
+		/* looks like a G3 powermac */
+		set_config_access_method(grackle);
+	} else {
+		set_config_access_method(pmac);
+	}
+
+	ppc_md.pcibios_fixup = pmac_pcibios_fixup;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.2.7/linux/arch/ppc/kernel/pmac_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_pic.c	Tue May 11 08:24:32 1999
@@ -0,0 +1,362 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include "pmac_pic.h"
+
+/* pmac */struct pmac_irq_hw {
+        unsigned int    flag;
+        unsigned int    enable;
+        unsigned int    ack;
+        unsigned int    level;
+};
+
+/* XXX these addresses should be obtained from the device tree */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
+        (struct pmac_irq_hw *) 0xf3000020,
+        (struct pmac_irq_hw *) 0xf3000010,
+        (struct pmac_irq_hw *) 0xf4000020,
+        (struct pmac_irq_hw *) 0xf4000010,
+};
+
+static int max_irqs;
+static int max_real_irqs;
+
+#define MAXCOUNT 10000000
+
+#define GATWICK_IRQ_POOL_SIZE        10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
+
+static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        do {
+                /* make sure ack gets to controller before we enable
+                   interrupts */
+                mb();
+        } while(in_le32(&pmac_irq_hw[i]->flag) & bit);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        /* enable unmasked interrupts */
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+        do {
+                /* make sure mask gets to controller before we
+                   return to user */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+
+        /*
+         * Unfortunately, setting the bit in the enable register
+         * when the device interrupt is already on *doesn't* set
+         * the bit in the flag register or request another interrupt.
+         */
+        if ((bit & ppc_cached_irq_mask[i])
+            && (ld_le32(&pmac_irq_hw[i]->level) & bit)
+            && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
+                if (!test_and_set_bit(irq_nr, ppc_lost_interrupts))
+                        atomic_inc(&ppc_n_lost_interrupts);
+        }
+}
+
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
+{
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr);
+        mb();
+}
+
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
+{
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr);
+}
+
+struct hw_interrupt_type pmac_pic = {
+        " PMAC-PIC ",
+        NULL,
+        NULL,
+        NULL,
+        pmac_unmask_irq,
+        pmac_mask_irq,
+        pmac_mask_and_ack_irq,
+        0
+};
+
+struct hw_interrupt_type gatwick_pic = {
+	" GATWICK  ",
+	NULL,
+	NULL,
+	NULL,
+	pmac_unmask_irq,
+	pmac_mask_irq,
+	pmac_mask_and_ack_irq,
+	0
+};
+
+static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int irq, bits;
+	
+	for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
+		int i = irq >> 5;
+		bits = ld_le32(&pmac_irq_hw[i]->flag)
+			| ppc_lost_interrupts[i];
+		if (bits == 0)
+			continue;
+		irq -= cntlzw(bits);
+		break;
+	}
+	/* The previous version of this code allowed for this case, we
+	 * don't.  Put this here to check for it.
+	 * -- Cort
+	 */
+	if ( irq_desc[irq].ctl != &gatwick_pic )
+		printk("gatwick irq not from gatwick pic\n");
+	else
+		ppc_irq_dispatch_handler( regs, irq );
+}
+
+void
+pmac_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
+{
+	int irq;
+	unsigned long bits = 0;
+
+#ifdef __SMP__
+        /* IPI's are a hack on the powersurge -- Cort */
+        if ( cpu != 0 )
+        {
+                if (!isfake)
+                {
+#ifdef CONFIG_XMON
+                        static int xmon_2nd;
+                        if (xmon_2nd)
+                                xmon(regs);
+#endif
+                        smp_message_recv();
+                        goto out;
+                }
+                /* could be here due to a do_fake_interrupt call but we don't
+                   mess with the controller from the second cpu -- Cort */
+                goto out;
+        }
+
+        {
+                unsigned int loops = MAXCOUNT;
+                while (test_bit(0, &global_irq_lock)) {
+                        if (smp_processor_id() == global_irq_holder) {
+                                printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                                break;
+                        }
+                        if (loops-- == 0) {
+                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                        }
+                }
+        }
+#endif /* __SMP__ */
+
+        for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+                int i = irq >> 5;
+                bits = ld_le32(&pmac_irq_hw[i]->flag)
+                        | ppc_lost_interrupts[i];
+                if (bits == 0)
+                        continue;
+                irq -= cntlzw(bits);
+                break;
+        }
+
+        if (irq < 0)
+        {
+                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                ppc_spurious_interrupts++;
+        }
+        else
+        {
+                ppc_irq_dispatch_handler( regs, irq );
+        }
+#ifdef CONFIG_SMP	
+out:
+#endif /* CONFIG_SMP */
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+	struct device_node *node;
+	int count;
+	
+	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+	node = gw->child;
+	count = 0;
+	while(node)
+	{
+		/* Fix SCC */
+		if (strcasecmp(node->name, "escc") == 0)
+			if (node->child) {
+				if (node->child->n_intrs < 3) {
+					node->child->intrs = &gatwick_int_pool[count];
+					count += 3;
+				}
+				node->child->n_intrs = 3;				
+				node->child->intrs[0].line = 15+irq_base;
+				node->child->intrs[1].line =  4+irq_base;
+				node->child->intrs[2].line =  5+irq_base;
+				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+					node->child->intrs[0].line,
+					node->child->intrs[1].line,
+					node->child->intrs[2].line);
+			}
+		/* Fix media-bay & left SWIM */
+		if (strcasecmp(node->name, "media-bay") == 0) {
+			struct device_node* ya_node;
+
+			if (node->n_intrs == 0)
+				node->intrs = &gatwick_int_pool[count++];
+			node->n_intrs = 1;
+			node->intrs[0].line = 29+irq_base;
+			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+					node->intrs[0].line);
+			
+			ya_node = node->child;
+			while(ya_node)
+			{
+				if (strcasecmp(ya_node->name, "floppy") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 19+irq_base;
+					ya_node->intrs[1].line =  1+irq_base;
+					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				if (strcasecmp(ya_node->name, "ata4") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 14+irq_base;
+					ya_node->intrs[1].line =  3+irq_base;
+					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				ya_node = ya_node->sibling;
+			}
+		}
+		node = node->sibling;
+	}
+	if (count > 10) {
+		printk("WARNING !! Gatwick interrupt pool overflow\n");
+		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+		printk("              requested = %d\n", count);
+	}
+}
+
+__initfunc(void
+pmac_pic_init(void))
+{
+        int i;
+        struct device_node *irqctrler;
+        unsigned long addr;
+	int second_irq = -999;
+
+
+	/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
+	   others have 32 */
+	max_irqs = max_real_irqs = 32;
+	irqctrler = find_devices("mac-io");
+	if (irqctrler)
+	{
+		max_real_irqs = 64;
+		if (irqctrler->next)
+			max_irqs = 128;
+		else
+			max_irqs = 64;
+	}
+	for ( i = 0; i < max_real_irqs ; i++ )
+		irq_desc[i].ctl = &pmac_pic;
+
+	/* get addresses of first controller */
+	if (irqctrler) {
+		if  (irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 0; i < 2; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (2 - i) * 0x10);
+		}
+		
+		/* get addresses of second controller */
+		irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+		if (irqctrler && irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 2; i < 4; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (4 - i) * 0x10);
+		}
+	}
+
+	/* disable all interrupts in all controllers */
+	for (i = 0; i * 32 < max_irqs; ++i)
+		out_le32(&pmac_irq_hw[i]->enable, 0);
+	
+	/* get interrupt line of secondary interrupt controller */
+	if (irqctrler) {
+		second_irq = irqctrler->intrs[0].line;
+		printk(KERN_INFO "irq: secondary controller on irq %d\n",
+			(int)second_irq);
+		if (device_is_compatible(irqctrler, "gatwick"))
+			pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+		for ( i = max_real_irqs ; i < max_irqs ; i++ )
+			irq_desc[i].ctl = &gatwick_pic;
+		request_irq( second_irq, gatwick_action, SA_INTERRUPT,
+			     "gatwick cascade", 0 );
+	}
+	printk("System has %d possible interrupts\n", max_irqs);
+	if (max_irqs != max_real_irqs)
+		printk(KERN_DEBUG "%d interrupts on main controller\n",
+			max_real_irqs);
+
+#ifdef CONFIG_XMON
+	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
+#endif	/* CONFIG_XMON */
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_pic.h linux/arch/ppc/kernel/pmac_pic.h
--- v2.2.7/linux/arch/ppc/kernel/pmac_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_pic.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,15 @@
+#ifndef _PPC_KERNEL_PMAC_PIC_H
+#define _PPC_KERNEL_PMAC_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+void pmac_do_IRQ(struct pt_regs *regs,
+                 int            cpu,
+                 int            isfake);
+
+
+#endif /* _PPC_KERNEL_PMAC_PIC_H */
+
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.2.7/linux/arch/ppc/kernel/pmac_setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/pmac_setup.c	Tue May 11 08:24:32 1999
@@ -44,6 +44,7 @@
X #include <asm/prom.h>
X #include <asm/system.h>
X #include <asm/pgtable.h>
+#include <asm/bitops.h>
X #include <asm/io.h>
X #include <asm/pci-bridge.h>
X #include <asm/adb.h>
@@ -52,7 +53,38 @@
X #include <asm/ohare.h>
X #include <asm/mediabay.h>
X #include <asm/feature.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
X #include "time.h"
+#include "local_irq.h"
+#include "pmac_pic.h"
+
+#undef SHOW_GATWICK_IRQS
+
+unsigned long pmac_get_rtc_time(void);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+void pmac_calibrate_decr(void);
+void pmac_setup_pci_ptrs(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128];
+#endif /* CONFIG_MAGIC_SYSRQ */
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
X 
X unsigned char drive_info;
X 
@@ -291,15 +323,12 @@
X int boot_part;
X kdev_t boot_dev;
X 
-void __init powermac_init(void)
+__initfunc(void
+pmac_init2(void))
X {
-  	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;
X 	adb_init();
X 	pmac_nvram_init();
-	if (_machine == _MACH_Pmac) {
-		media_bay_init();
-	}
+	media_bay_init();
X }
X 
X #ifdef CONFIG_SCSI
@@ -402,5 +431,176 @@
X 		boot_dev = NODEV;
X 		printk(" (root)");
X 	}
+}
+
+void
+pmac_restart(char *cmd)
+{
+	struct adb_request req;
+
+	switch (adb_hardware) {
+	case ADB_VIACUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_RESET_SYSTEM);
+		for (;;)
+			cuda_poll();
+		break;
+
+	case ADB_VIAPMU:
+		pmu_restart();
+		break;
+	default:
+	}
+}
+
+void
+pmac_power_off(void)
+{
+	struct adb_request req;
+
+	switch (adb_hardware) {
+	case ADB_VIACUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_POWERDOWN);
+		for (;;)
+			cuda_poll();
+		break;
+
+	case ADB_VIAPMU:
+		pmu_shutdown();
+		break;
+	default:
+	}
+}
+
+void
+pmac_halt(void)
+{
+   pmac_power_off();
+}
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port, buf, ns);
+}
+
+void
+pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port, buf, ns);
+}
+
+int
+pmac_ide_default_irq(ide_ioreg_t base)
+{
+        return 0;
+}
+
+ide_ioreg_t
+pmac_ide_default_io_base(int index)
+{
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+        return pmac_ide_regbase[index];
+#else
+	return 0;
+#endif
+}
+
+int
+pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return 0;
+}
+
+void
+pmac_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+}
+
+void
+pmac_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+}
+
+/* Convert the shorts/longs in hd_driveid from little to big endian;
+ * chars are endian independant, of course, but strings need to be flipped.
+ * (Despite what it says in drivers/block/ide.h, they come up as little
+ * endian...)
+ *
+ * Changes to linux/hdreg.h may require changes here. */
+void
+pmac_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+/* This is declared in drivers/block/ide-pmac.c */
+void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+#endif
+
+__initfunc(void
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+	pmac_setup_pci_ptrs();
+
+	/* isa_io_base gets set in pmac_find_bridges */
+	isa_mem_base = PMAC_ISA_MEM_BASE;
+	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 1;
+	DMA_MODE_WRITE = 2;
+
+	ppc_md.setup_arch     = pmac_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = pmac_get_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = pmac_pic_init;
+	ppc_md.do_IRQ         = pmac_do_IRQ;
+	ppc_md.init           = pmac_init2;
+
+	ppc_md.restart        = pmac_restart;
+	ppc_md.power_off      = pmac_power_off;
+	ppc_md.halt           = pmac_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = pmac_set_rtc_time;
+	ppc_md.get_rtc_time   = pmac_get_rtc_time;
+	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
+	ppc_md.kbd_setkeycode    = mackbd_setkeycode;
+	ppc_md.kbd_getkeycode    = mackbd_getkeycode;
+	ppc_md.kbd_translate     = mackbd_translate;
+	ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
+	ppc_md.kbd_leds          = mackbd_leds;
+	ppc_md.kbd_init_hw       = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+        ppc_ide_md.insw = pmac_ide_insw;
+        ppc_ide_md.outsw = pmac_ide_outsw;
+        ppc_ide_md.default_irq = pmac_ide_default_irq;
+        ppc_ide_md.default_io_base = pmac_ide_default_io_base;
+        ppc_ide_md.check_region = pmac_ide_check_region;
+        ppc_ide_md.request_region = pmac_ide_request_region;
+        ppc_ide_md.release_region = pmac_ide_release_region;
+        ppc_ide_md.fix_driveid = pmac_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = 0;
+#endif		
X }
X 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
--- v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc8xx_pic.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,49 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/mbx.h>
+#include "ppc8xx_pic.h"
+
+
+static void mbx_mask_irq(unsigned int irq_nr)
+{
+	if ( irq_nr == ISA_BRIDGE_INT ) return;
+	if ( irq_nr >= ppc8xx_pic.irq_offset )
+		irq_nr -= ppc8xx_pic.irq_offset;
+	ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+}
+
+static void mbx_unmask_irq(unsigned int irq_nr)
+{
+	if ( irq_nr >= ppc8xx_pic.irq_offset )
+		irq_nr -= ppc8xx_pic.irq_offset;
+	ppc_cached_irq_mask[0] |= (1 << (31-irq_nr));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+}
+
+static void mbx_mask_and_ack(unsigned int irq_nr)
+{
+	/* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
+	if ( irq_nr != ISA_BRIDGE_INT )
+		mbx_mask_irq(irq_nr);
+	if ( irq_nr >= ppc8xx_pic.irq_offset )
+		irq_nr -= ppc8xx_pic.irq_offset;
+	/* clear the pending bits */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
+}
+
+struct hw_interrupt_type ppc8xx_pic = {
+	" 8xx SIU  ",
+	NULL,
+	NULL,
+	NULL,
+	mbx_unmask_irq,
+	mbx_mask_irq,
+	mbx_mask_and_ack,
+	0
+};
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.h linux/arch/ppc/kernel/ppc8xx_pic.h
--- v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc8xx_pic.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,9 @@
+
+#ifndef _PPC_KERNEL_PPC8xx_H
+#define _PPC_KERNEL_PPC8xx_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type ppc8xx_pic;
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.2.7/linux/arch/ppc/kernel/ppc_ksyms.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Thu Apr 29 12:39:01 1999
@@ -27,6 +27,8 @@
X #include <asm/irq.h>
X #include <asm/feature.h>
X #include <asm/spinlock.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
X 
X #define __KERNEL_SYSCALLS__
X #include <linux/unistd.h>
@@ -40,7 +42,7 @@
X extern void ProgramCheckException(struct pt_regs *regs);
X extern void SingleStepException(struct pt_regs *regs);
X extern int sys_sigreturn(struct pt_regs *regs);
-extern atomic_t n_lost_interrupts;
+extern atomic_t ppc_n_lost_interrupts;
X extern void do_lost_interrupts(unsigned long);
X extern int do_signal(sigset_t *, struct pt_regs *);
X 
@@ -59,16 +61,21 @@
X EXPORT_SYMBOL(ProgramCheckException);
X EXPORT_SYMBOL(SingleStepException);
X EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(n_lost_interrupts);
+EXPORT_SYMBOL(ppc_n_lost_interrupts);
X EXPORT_SYMBOL(do_lost_interrupts);
X EXPORT_SYMBOL(enable_irq);
X EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(ppc_local_irq_count);
+EXPORT_SYMBOL(ppc_local_bh_count);
X 
X EXPORT_SYMBOL(isa_io_base);
X EXPORT_SYMBOL(isa_mem_base);
X EXPORT_SYMBOL(pci_dram_offset);
+EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
+EXPORT_SYMBOL(DMA_MODE_READ);
+EXPORT_SYMBOL(DMA_MODE_WRITE);
+EXPORT_SYMBOL(_prep_type);
+EXPORT_SYMBOL(ucSystemType);
X 
X EXPORT_SYMBOL(atomic_add);
X EXPORT_SYMBOL(atomic_sub);
@@ -157,6 +164,7 @@
X EXPORT_SYMBOL(flush_instruction_cache);
X EXPORT_SYMBOL(_get_PVR);
X EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(enable_kernel_fp);
X EXPORT_SYMBOL(flush_icache_range);
X EXPORT_SYMBOL(xchg_u32);
X #ifdef __SMP__
@@ -173,18 +181,14 @@
X EXPORT_SYMBOL(_write_unlock);
X #endif
X 
-#ifndef CONFIG_MACH_SPECIFIC
X EXPORT_SYMBOL(_machine);
-#endif
+EXPORT_SYMBOL(ppc_md);
X 
X EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_autopoll);
X EXPORT_SYMBOL(adb_register);
X EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_send_request);
X EXPORT_SYMBOL(cuda_poll);
X EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_send_request);
X EXPORT_SYMBOL(pmu_poll);
X #ifdef CONFIG_PMAC_PBOOK
X EXPORT_SYMBOL(sleep_notifier_list);
@@ -196,7 +200,6 @@
X EXPORT_SYMBOL(find_path_device);
X EXPORT_SYMBOL(find_phandle);
X EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(device_is_compatible);
X EXPORT_SYMBOL(pci_io_base);
X EXPORT_SYMBOL(pci_device_loc);
X EXPORT_SYMBOL(feature_set);
@@ -211,9 +214,8 @@
X EXPORT_SYMBOL(nvram_write_byte);
X #endif /* CONFIG_PMAC */
X 
-#ifdef CONFIG_SOUND_MODULE
X EXPORT_SYMBOL(abs);
-#endif
+EXPORT_SYMBOL(device_is_compatible);
X 
X /* The following are special because they're not called
X    explicitly (the C compiler generates them).  Fortunately,
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_nvram.c linux/arch/ppc/kernel/prep_nvram.c
--- v2.2.7/linux/arch/ppc/kernel/prep_nvram.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/prep_nvram.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,173 @@
+/*
+ *  linux/arch/ppc/kernel/prep_nvram.c
+ *
+ *  Copyright (C) 1998  Corey Minyard
+ *
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+
+/*
+ * Allow for a maximum of 32K of PReP NvRAM data
+ */
+#define MAX_PREP_NVRAM 0x8000
+static char nvramData[MAX_PREP_NVRAM];
+static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
+
+#define PREP_NVRAM_AS0	0x74
+#define PREP_NVRAM_AS1	0x75
+#define PREP_NVRAM_DATA	0x77
+
+unsigned char *rs_pcNvRAM;
+
+unsigned char prep_nvram_read_val(int addr)
+{
+	outb(addr, PREP_NVRAM_AS0);
+	outb(addr>>8, PREP_NVRAM_AS1);
+	return inb(PREP_NVRAM_DATA);
+}
+  
+void prep_nvram_write_val(int           addr,
+			  unsigned char val)
+{
+	outb(addr, PREP_NVRAM_AS0);
+	outb(addr>>8, PREP_NVRAM_AS1);
+   	outb(val, PREP_NVRAM_DATA);
+}
+  
+/*
+ * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space
+ */
+unsigned char rs_nvram_read_val(int addr)
+{
+	return rs_pcNvRAM[addr];
+}
+  
+void rs_nvram_write_val(int addr,
+			unsigned char val)
+{
+	rs_pcNvRAM[addr]=val;
+}
+  
+__initfunc(void init_prep_nvram(void))
+{
+	unsigned char *nvp;
+	int  i;
+	int  nvramSize;
+
+	/*
+	 * I'm making the assumption that 32k will always cover the
+	 * nvramsize.  If this isn't the case please let me know and we can
+	 * map the header, then get the size from the header, then map
+	 * the whole size. -- Cort
+	 */
+	if ( _prep_type == _PREP_Radstone )
+		rs_pcNvRAM = (unsigned char *)ioremap(_ISA_MEM_BASE+0x00800000,
+						      32<<10);
+	request_region(PREP_NVRAM_AS0, 0x8, "PReP NVRAM");
+	/*
+	 * The following could fail if the NvRAM were corrupt but
+	 * we expect the boot firmware to have checked its checksum
+	 * before boot
+	 */
+	nvp = (char *) &nvram->Header;
+	for (i=0; i<sizeof(HEADER); i++)
+	{
+		*nvp = ppc_md.nvram_read_val(i);
+		nvp++;
+	}
+	
+	/*
+	 * The PReP NvRAM may be any size so read in the header to
+	 * determine how much we must read in order to get the complete
+	 * GE area
+	 */
+	nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength;
+	if(nvramSize>MAX_PREP_NVRAM)
+	{
+		/*
+		 * NvRAM is too large
+		 */
+		nvram->Header.GELength=0;
+		return;
+	}
+
+	/*
+	 * Read the remainder of the PReP NvRAM
+	 */
+	nvp = (char *) &nvram->GEArea[0];
+	for (i=sizeof(HEADER); i<nvramSize; i++)
+	{
+		*nvp = ppc_md.nvram_read_val(i);
+		nvp++;
+	}
+}
+
+__prep
+char *prep_nvram_get_var(const char *name)
+{
+	char *cp;
+	int  namelen;
+
+	namelen = strlen(name);
+	cp = prep_nvram_first_var();
+	while (cp != NULL) {
+		if ((strncmp(name, cp, namelen) == 0)
+		    && (cp[namelen] == '='))
+		{
+			return cp+namelen+1;
+		}
+		cp = prep_nvram_next_var(cp);
+	}
+
+	return NULL;
+}
+
+__prep
+char *prep_nvram_first_var(void)
+{
+        if (nvram->Header.GELength == 0) {
+		return NULL;
+	} else {
+		return (((char *)nvram)
+			+ ((unsigned int) nvram->Header.GEAddress));
+	}
+}
+
+__prep
+char *prep_nvram_next_var(char *name)
+{
+	char *cp;
+
+
+	cp = name;
+	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+	       && (*cp != '\0'))
+	{
+		cp++;
+	}
+
+	/* Skip over any null characters. */
+	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+	       && (*cp == '\0'))
+	{
+		cp++;
+	}
+
+	if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) {
+		return cp;
+	} else {
+		return NULL;
+	}
+}
+
+
+
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.2.7/linux/arch/ppc/kernel/prep_pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prep_pci.c	Tue May 11 08:24:32 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: prep_pci.c,v 1.25 1999/03/03 15:09:45 cort Exp $
+ * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
X  * PReP pci functions.
X  * Originally by Gary Thomas
X  * rewritten and updated by Cort Dougan (co...@cs.nmt.edu)
@@ -11,11 +11,19 @@
X #include <linux/pci.h>
X #include <linux/kernel.h>
X #include <linux/init.h>
+#include <linux/openpic.h>
X 
X #include <asm/byteorder.h>
X #include <asm/io.h>
X #include <asm/ptrace.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/residual.h>
X #include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
X 
X #define MAX_DEVNR 22
X 
@@ -27,6 +35,9 @@
X /* How is the 82378 PIRQ mapping setup? */
X unsigned char *Motherboard_routes;
X 
+/* Used for Motorola to store system config register */
+static unsigned long	*ProcInfo;
+
X /* Tables for known hardware */   
X 
X /* Motorola PowerStackII - Utah */
@@ -34,38 +45,39 @@
X {
X         0,   /* Slot 0  - unused */
X         0,   /* Slot 1  - unused */
-        4,   /* Slot 2  - SCSI - NCR825A  */
+        5,   /* Slot 2  - SCSI - NCR825A  */
X         0,   /* Slot 3  - unused */
X         1,   /* Slot 4  - Ethernet - DEC2114x */
X         0,   /* Slot 5  - unused */
-        2,   /* Slot 6  - PCI Card slot #1 */
-        3,   /* Slot 7  - PCI Card slot #2 */
-        4,   /* Slot 8  - PCI Card slot #3 */
-        4,   /* Slot 9  - PCI Bridge */
+        3,   /* Slot 6  - PCI Card slot #1 */
+        4,   /* Slot 7  - PCI Card slot #2 */
+        5,   /* Slot 8  - PCI Card slot #3 */
+        5,   /* Slot 9  - PCI Bridge */
X              /* added here in case we ever support PCI bridges */
X              /* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
X         0,   /* Slot 10 - unused */
X         0,   /* Slot 11 - unused */
-        4,   /* Slot 12 - SCSI - NCR825A */
+        5,   /* Slot 12 - SCSI - NCR825A */
X         0,   /* Slot 13 - unused */
-        2,   /* Slot 14 - enet */
+        3,   /* Slot 14 - enet */
X         0,   /* Slot 15 - unused */
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
+        2,   /* Slot 16 - unused */
+        3,   /* Slot 17 - unused */
+        5,   /* Slot 18 - unused */
+        0,   /* Slot 19 - unused */
+        0,   /* Slot 20 - unused */
+        0,   /* Slot 21 - unused */
+        0,   /* Slot 22 - unused */
X };
X 
X static char Utah_pci_IRQ_routes[] __prepdata =
X {
X         0,   /* Line 0 - Unused */
X         9,   /* Line 1 */
-        11,  /* Line 2 */
-        14,  /* Line 3 */
-        15,  /* Line 4 */
+	10,  /* Line 2 */
+        11,  /* Line 3 */
+        14,  /* Line 4 */
+        15,  /* Line 5 */
X };
X 
X /* Motorola PowerStackII - Omaha */
@@ -125,9 +137,9 @@
X   	0,	/* Slot 13 - unused */
X   	1,	/* Slot 14 - Ethernet */
X   	0,	/* Slot 15 - unused */
-  	1,	/* Slot P7 */
-  	2,	/* Slot P6 */
-  	3,	/* Slot P5 */
+ 	1,	/* Slot P7 */
+ 	2,	/* Slot P6 */
+ 	3,	/* Slot P5 */
X };
X 
X static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -139,6 +151,122 @@
X    	15	/* Line 4 */
X };
X    
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unxued */
+	0,	/* Slot 11 - unused */
+	0,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	3,	/* Slot 16 - PMC */
+	0,	/* Slot 17 - unused */
+	0,	/* Slot 18 - unused */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+	0,      /* Slot 0  - unused */
+	0,      /* Slot 1  - unused */
+	0,      /* Slot 2  - unused */
+	0,      /* Slot 3  - unused */
+	0,      /* Slot 4  - unused */
+	0,      /* Slot 5  - unused */
+	0,      /* Slot 6  - unused */
+	0,      /* Slot 7  - unused */
+	0,      /* Slot 8  - unused */
+	0,      /* Slot 9  - unused */
+	0,      /* Slot 10 - unxued */
+	0,      /* Slot 11 - unused */
+	0,      /* Slot 12 - unused */
+	0,      /* Slot 13 - unused */
+	2,      /* Slot 14 - Ethernet */
+	0,      /* Slot 15 - unused */
+	9,      /* Slot 16 - PMC 1  */
+	12,     /* Slot 17 - PMC 2  */
+	0,      /* Slot 18 - unused */
+	0,      /* Slot 19 - unused */
+	4,      /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+	3,	/* Slot 12 - SCSI */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - Ethernet */
+	0,	/* Slot 15 - unused */
+	9,      /* Slot 16 - PCI/PMC slot 1 */
+	10,     /* Slot 17 - PCI/PMC slot 2 */
+	11,     /* Slot 18 - PCI slot 3 */
+	0,	/* Slot 19 - unused */
+	0,	/* Slot 20 - unused */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+        0,      /* Slot 0  - unused */
+        0,      /* Slot 1  - unused */
+        0,      /* Slot 2  - unused */
+        0,      /* Slot 3  - unused */
+        0,      /* Slot 4  - unused */
+        0,      /* Slot 5  - unused */
+        0,      /* Slot 6  - unused */
+        0,      /* Slot 7  - unused */
+        0,      /* Slot 8  - unused */
+        0,      /* Slot 9  - unused */
+        0,      /* Slot 10 - unused */
+        0,      /* Slot 11 - unused */
+        3,      /* Slot 12 - SCSI */
+        0,      /* Slot 13 - unused */
+        2,      /* Slot 14 - Ethernet 1 */
+        0,      /* Slot 15 - unused */
+        9,      /* Slot 16 - PCI slot 1P */
+        10,     /* Slot 17 - PCI slot 2P */
+        11,     /* Slot 18 - PCI slot 3P */
+        10,     /* Slot 19 - Ethernet 2 */
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 10'
echo 'File patch-2.2.8 is continued in part 11'
echo 11 > _shar_seq_.tmp
#!/bin/sh
# this is part 11 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 11; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+ 0, /* Slot 20 - P2P Bridge */
+        0,      /* Slot 21 - unused */
+        0,      /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+   	0,	/* This is a dummy structure */
+};
+   
X /* Motorola MVME16xx */
X static char Genesis_pci_IRQ_map[16] __prepdata =
X {
@@ -169,8 +297,35 @@
X    	15	/* Line 4 */
X };
X    
+static char Genesis2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+	0,	/* Slot 2  - unused */
+	0,	/* Slot 3  - unused */
+	0,	/* Slot 4  - unused */
+	0,	/* Slot 5  - unused */
+	0,	/* Slot 6  - unused */
+	0,	/* Slot 7  - unused */
+	0,	/* Slot 8  - unused */
+	0,	/* Slot 9  - unused */
+	0,	/* Slot 10 - Ethernet */
+	0,	/* Slot 11 - Universe PCI - VME Bridge */
+	3,	/* Slot 12 - unused */
+	0,	/* Slot 13 - unused */
+	2,	/* Slot 14 - SCSI */
+	0,	/* Slot 15 - graphics on 3600 */
+	9,	/* Slot 16 - PMC */
+	12,	/* Slot 17 - pci */
+	11,	/* Slot 18 - pci */
+	10,	/* Slot 19 - pci */
+	0,	/* Slot 20 - pci */
+	0,	/* Slot 21 - unused */
+	0,	/* Slot 22 - unused */
+};
+
X /* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] __prepdata =
+static char Comet_pci_IRQ_map[23] __prepdata =
X {
X   	0,	/* Slot 0  - unused */
X   	0,	/* Slot 1  - unused */
@@ -188,6 +343,13 @@
X   	0,	/* Slot 13 - unused */
X   	1,	/* Slot 14 - Ethernet */
X   	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
X };
X 
X static char Comet_pci_IRQ_routes[] __prepdata =
@@ -199,6 +361,43 @@
X    	15	/* Line 4 */
X };
X 
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+	0,	/* Slot 0  - unused */
+	0,	/* Slot 1  - unused */
+ 3, /* Slot 2 - SCSI - NCR825A */
+	0,	/* Slot 3  - unused */
+ 1, /* Slot 4 - Ethernet - DEC2104X */
+	0,	/* Slot 5  - unused */
+	1,	/* Slot 6  - PCI slot 1 */
+	2,	/* Slot 7  - PCI slot 2 */
+	3,	/* Slot 8  - PCI slot 3 */
+	4,	/* Slot 9  - PCI bridge  */
+	0,	/* Slot 10 - unused */
+	0,	/* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI - NCR825A */
+	0,	/* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet - DEC2104X */
+	0,	/* Slot 15 - unused */
+	1,	/* Slot 16 - PCI slot 1 */
+	2,	/* Slot 17 - PCI slot 2 */
+	3,	/* Slot 18 - PCI slot 3 */
+	4,	/* Slot 19 - PCI bridge */
+	0,
+	0,
+	0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+	0,	/* Line 0 - Unused */
+	10,	/* Line 1 */
+	11,	/* Line 2 */
+	14,	/* Line 3 */
+	15,	/* Line 4 */
+};
+
X /*
X  * ibm 830 (and 850?).
X  * This is actually based on the Carolina motherboard
@@ -328,106 +527,24 @@
X #define ELCRM_INT7_LVL          0x80
X #define ELCRM_INT5_LVL          0x20
X 
-/*
- * Mechanism 1 configuration space access as defined in the PCI spec.
- */
-#define CFG_ADDR (volatile u_int *)0x80000cf8
-#define CFG_DATA 0x80000cfc
-
-#define CFG_DEV_ADDR(b, d, o)	(0x80000000 |	\
-				 ((b) << 16) |	\
-				 ((d) << 8) |	\
-				 ((o) & ~3))
-
-unsigned char max_bus=255;
-
-int mech1_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned char *val)
-{
-	*val = 0xff;
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	*val = in_8((unsigned char *)CFG_DATA + (offset & 3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned short *val)
-{
-	*val = 0xffff;
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 1) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	*val = in_le16((volatile unsigned short *)(CFG_DATA + (offset&3)));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned int *val)
-{
-	*val = 0xffffffff;
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 3) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	*val = in_le32((volatile unsigned int *)CFG_DATA);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned char val)
-{
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	out_8((unsigned char *)CFG_DATA + (offset & 3), val);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned short val)
-{
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 1) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	out_le16((volatile unsigned short *)(CFG_DATA + (offset&3)), val);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-				    unsigned char offset, unsigned int val)
-{
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 1) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	out_le32((volatile unsigned int *)CFG_DATA, val);
-	return PCIBIOS_SUCCESSFUL;
-}
+#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
+#define DEVNO(dev)  (dev>>3)                                  
X 
X __prep
X int
X prep_pcibios_read_config_dword (unsigned char bus,
X 			   unsigned char dev, unsigned char offset, unsigned int *val)
X {
-	unsigned long _val;
+	unsigned long _val;                                          
X 	unsigned long *ptr;
-	dev >>= 3;
-	
-	if ((bus != 0) || (dev > MAX_DEVNR))
-	{
+
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+	{                   
X 		*val = 0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
+		return PCIBIOS_DEVICE_NOT_FOUND;    
+	} else                                                                
X 	{
-		ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned long *)CFGPTR(dev);
X 		_val = le32_to_cpu(*ptr);
X 	}
X 	*val = _val;
@@ -439,16 +556,16 @@
X prep_pcibios_read_config_word (unsigned char bus,
X 			  unsigned char dev, unsigned char offset, unsigned short *val)
X {
-	unsigned short _val;
+	unsigned short _val;                                          
X 	unsigned short *ptr;
-	dev >>= 3;
-	if ((bus != 0) || (dev > MAX_DEVNR))
-	{
-		*val = (unsigned short)0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
+
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+	{                   
+		*val = 0xFFFF;
+		return PCIBIOS_DEVICE_NOT_FOUND;    
+	} else                                                                
X 	{
-		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned short *)CFGPTR(dev);
X 		_val = le16_to_cpu(*ptr);
X 	}
X 	*val = _val;
@@ -460,16 +577,16 @@
X prep_pcibios_read_config_byte (unsigned char bus,
X 			  unsigned char dev, unsigned char offset, unsigned char *val)
X {
-	unsigned char _val;
-	volatile unsigned char *ptr;
-	dev >>= 3;
-	if ((bus != 0) || (dev > MAX_DEVNR))
-	{
-		*(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
+	unsigned char _val;                                          
+	unsigned char *ptr;
+
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+	{                   
+		*val = 0xFF;
+		return PCIBIOS_DEVICE_NOT_FOUND;    
+	} else                                                                
X 	{
-		ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1));
+		ptr = (unsigned char *)CFGPTR(dev);
X 		_val = *ptr;
X 	}
X 	*val = _val;
@@ -483,14 +600,14 @@
X {
X 	unsigned long _val;
X 	unsigned long *ptr;
-	dev >>= 3;
+
X 	_val = le32_to_cpu(val);
-	if ((bus != 0) || (dev > MAX_DEVNR))
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
X 	{
X 		return PCIBIOS_DEVICE_NOT_FOUND;
X 	} else
X 	{
-		ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned long *)CFGPTR(dev);
X 		*ptr = _val;
X 	}
X 	return PCIBIOS_SUCCESSFUL;
@@ -503,14 +620,14 @@
X {
X 	unsigned short _val;
X 	unsigned short *ptr;
-	dev >>= 3;
+
X 	_val = le16_to_cpu(val);
-	if ((bus != 0) || (dev > MAX_DEVNR))
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
X 	{
X 		return PCIBIOS_DEVICE_NOT_FOUND;
X 	} else
X 	{
-		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned short *)CFGPTR(dev);
X 		*ptr = _val;
X 	}
X 	return PCIBIOS_SUCCESSFUL;
@@ -523,20 +640,151 @@
X {
X 	unsigned char _val;
X 	unsigned char *ptr;
-	dev >>= 3;
+
X 	_val = val;
-	if ((bus != 0) || (dev > MAX_DEVNR))
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
X 	{
X 		return PCIBIOS_DEVICE_NOT_FOUND;
X 	} else
X 	{
-		ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset^1));
+		ptr = (unsigned char *)CFGPTR(dev);
X 		*ptr = _val;
X 	}
X 	return PCIBIOS_SUCCESSFUL;
X }
X 
-__initfunc(unsigned long route_pci_interrupts(void))
+#define MOTOROLA_CPUTYPE_REG	0x800
+#define MOTOROLA_BASETYPE_REG	0x803
+#define MPIC_RAVEN_ID		0x48010000
+#define	MPIC_HAWK_ID		0x48030000
+#define	MOT_PROC2_BIT		0x800
+
+static u_char mvme2600_openpic_initsenses[] __initdata = {
+    1,	/* MVME2600_INT_SIO */
+    0,	/* MVME2600_INT_FALCN_ECC_ERR */
+    1,	/* MVME2600_INT_PCI_ETHERNET */
+    1,	/* MVME2600_INT_PCI_SCSI */
+    1,	/* MVME2600_INT_PCI_GRAPHICS */
+    1,	/* MVME2600_INT_PCI_VME0 */
+    1,	/* MVME2600_INT_PCI_VME1 */
+    1,	/* MVME2600_INT_PCI_VME2 */
+    1,	/* MVME2600_INT_PCI_VME3 */
+    1,	/* MVME2600_INT_PCI_INTA */
+    1,	/* MVME2600_INT_PCI_INTB */
+    1,	/* MVME2600_INT_PCI_INTC */
+    1,	/* MVME2600_INT_PCI_INTD */
+    1,	/* MVME2600_INT_LM_SIG0 */
+    1,	/* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT	0x1
+#define MOT_HAWK_PRESENT	0x2
+
+int prep_keybd_present = 1;
+int MotMPIC = 0;
+
+__initfunc(int raven_init(void))
+{
+	unsigned int	devid;
+	unsigned int	pci_membase;
+	unsigned char	base_mod;
+
+	/* Check to see if the Raven chip exists. */
+	if ( _prep_type != _PREP_Motorola) {
+		OpenPIC = NULL;
+		return 0;
+	}
+
+	/* Check to see if this board is a type that might have a Raven. */
+	if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+		OpenPIC = NULL;
+		return 0;
+	}
+
+	/* Check the first PCI device to see if it is a Raven. */
+	pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &devid);
+
+	switch (devid & 0xffff0000) {
+	case MPIC_RAVEN_ID:
+		MotMPIC = MOT_RAVEN_PRESENT;
+		break;
+	case MPIC_HAWK_ID:
+		MotMPIC = MOT_HAWK_PRESENT;
+		break;
+	default:
+		OpenPIC = NULL;
+		return 0;
+	}
+
+
+	/* Read the memory base register. */
+	pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+	if (pci_membase == 0) {
+		OpenPIC = NULL;
+		return 0;
+	}
+
+	/* Map the Raven MPIC registers to virtual memory. */
+	OpenPIC = (struct OpenPIC *)ioremap(pci_membase+0xC0000000, 0x22000);
+
+	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+	/* If raven is present on Motorola store the system config register
+	 * for later use.
+	 */
+	ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+	/* 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.
+	 */
+	base_mod = inb(MOTOROLA_BASETYPE_REG);
+	if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+	    (base_mod == 0xFA) || (base_mod == 0xE1))
+		prep_keybd_present = 0;
+
+	return 1;
+}
+
+struct mot_info {
+	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+					/* 0x200 if this board has a Hawk chip. */
+	int		base_type;
+	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
+	const char	*name;
+	unsigned char	*map;
+	unsigned char	*routes;
+} mot_info[] = {
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL}
+};
+
+__initfunc(unsigned long prep_route_pci_interrupts(void))
X {
X 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
X 	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
@@ -545,49 +793,66 @@
X 	if ( _prep_type == _PREP_Motorola)
X 	{
X 		unsigned short irq_mode;
+		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);
+
+		for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+			if (mot_info[entry].cpu_type & 0x200) {		 	/* Check for Hawk chip */
+				if (!(MotMPIC & MOT_HAWK_PRESENT))
+					continue;
+			} else {						/* Check non hawk boards */
+				if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+					continue;
+
+				if (mot_info[entry].base_type == 0) {
+					mot_entry = entry;
+					break;
+				}
X 
-		switch (inb(0x800) & 0xF0)
-		{
-		case 0x10: /* MVME16xx */
-			Motherboard_map_name = "Genesis";
-			Motherboard_map = Genesis_pci_IRQ_map;
-			Motherboard_routes = Genesis_pci_IRQ_routes;
-			break;
-		case 0x20: /* Series E */
-			Motherboard_map_name = "Powerstack (Series E)";
-			Motherboard_map = Comet_pci_IRQ_map;
-			Motherboard_routes = Comet_pci_IRQ_routes;
-			break;
-		case 0x50: /* PowerStackII Pro3000 */
-			Motherboard_map_name = "Omaha (PowerStack II Pro3000)";
-			Motherboard_map = Omaha_pci_IRQ_map;
-			Motherboard_routes = Omaha_pci_IRQ_routes;
-			break;
-		case 0x60: /* PowerStackII Pro4000 */
-			Motherboard_map_name = "Utah (Powerstack II Pro4000)";
-			Motherboard_map = Utah_pci_IRQ_map;
-			Motherboard_routes = Utah_pci_IRQ_routes;
-			break;
-                case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */
-                        Motherboard_map_name = "Motorola MTX";
-                        Motherboard_map = Genesis_pci_IRQ_map;
-                        Motherboard_routes = Genesis_pci_IRQ_routes;
-                        break;
-		case 0x40: /* PowerStack */
-		default: /* Can't hurt, can it? */
-			Motherboard_map_name = "Blackhawk (Powerstack)";
-			Motherboard_map = Blackhawk_pci_IRQ_map;
-			Motherboard_routes = Blackhawk_pci_IRQ_routes;
-			break;
+				if (mot_info[entry].base_type != base_mod)
+					continue;
+			}
+
+			if (!(mot_info[entry].max_cpu & 0x80)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 not present and max processor zero indicated */
+			if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
+
+			/* processor 1 present and max processor zero indicated */
+			if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+				mot_entry = entry;
+				break;
+			}
X 		}
-		/* AJF adjust level/edge control according to routes */
-		irq_mode = 0;
-		for (i = 1;  i <= 4;  i++)
-		{
-			irq_mode |= ( 1 << Motherboard_routes[i] );
+
+		if (mot_entry == -1) 	/* No particular cpu type found - assume Blackhawk */
+			mot_entry = 3;
+
+		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+		Motherboard_map = mot_info[mot_entry].map;
+		Motherboard_routes = mot_info[mot_entry].routes;
+
+		if (!(mot_info[entry].cpu_type & 0x100)) {
+			/* AJF adjust level/edge control according to routes */
+			irq_mode = 0;
+			for (i = 1;  i <= 4;  i++)
+			{
+				irq_mode |= ( 1 << Motherboard_routes[i] );
+			}
+			outb( irq_mode & 0xff, 0x4d0 );
+			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
X 		}
-		outb( irq_mode & 0xff, 0x4d0 );
-		outb( (irq_mode >> 8) & 0xff, 0x4d1 );
X 	} else if ( _prep_type == _PREP_IBM )
X 	{
X 		unsigned char pl_id;
@@ -705,5 +970,119 @@
X 	/* Enable PCI interrupts */
X 	*ibc_pcicon |= 0x20;
X 	return 0;
+}
+
+__initfunc(
+void
+prep_pcibios_fixup(void))
+{
+        struct pci_dev *dev;
+        extern unsigned char *Motherboard_map;
+        extern unsigned char *Motherboard_routes;
+        unsigned char i;
+
+        if ( _prep_type == _PREP_Radstone )
+        {
+                printk("Radstone boards require no PCI fixups\n");
+		return;
+        }
+
+	prep_route_pci_interrupts();
+
+	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+	if (OpenPIC) {
+		/* PCI interrupts are controlled by the OpenPIC */
+		for(dev=pci_devices; dev; dev=dev->next) {
+			if (dev->bus->number == 0) {
+                       		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
+			}
+		}
+		return;
+	}
+
+	for(dev=pci_devices; dev; dev=dev->next)
+	{
+		/*
+		 * Use our old hard-coded kludge to figure out what
+		 * irq this device uses.  This is necessary on things
+		 * without residual data. -- Cort
+		 */
+		unsigned char d = PCI_SLOT(dev->devfn);
+		dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+		for ( i = 0 ; i <= 5 ; i++ )
+		{
+		        if ( dev->base_address[i] > 0x10000000 )
+		        {
+		                printk("Relocating PCI address %lx -> %lx\n",
+		                       dev->base_address[i],
+		                       (dev->base_address[i] & 0x00FFFFFF)
+		                       | 0x01000000);
+		                dev->base_address[i] =
+		                  (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+		                pci_write_config_dword(dev,
+		                        PCI_BASE_ADDRESS_0+(i*0x4),
+		                       dev->base_address[i] );
+		        }
+		}
+#if 0
+		/*
+		 * If we have residual data and if it knows about this
+		 * device ask it what the irq is.
+		 *  -- Cort
+		 */
+		ppcd = residual_find_device_id( ~0L, dev->device,
+		                                -1,-1,-1, 0);
+#endif
+	}
+}
+
+decl_config_access_method(indirect);
+
+__initfunc(
+void
+prep_setup_pci_ptrs(void))
+{
+	PPC_DEVICE *hostbridge;
+
+        printk("PReP architecture\n");
+        if ( _prep_type == _PREP_Radstone )
+        {
+		pci_config_address = (unsigned *)0x80000cf8;
+		pci_config_data = (char *)0x80000cfc;
+                set_config_access_method(indirect);		
+        }
+        else
+        {
+                hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+		       BridgeController, PCIBridge, -1, 0);
+                if (hostbridge &&
+                    hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+                        PnP_TAG_PACKET * pkt;
+                        set_config_access_method(indirect);
+                        pkt = PnP_find_large_vendor_packet(
+				res->DevicePnPHeap+hostbridge->AllocatedOffset,
+				3, 0);
+                        if(pkt)
+			{
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+                                pci_config_address= (unsigned *)ld_le32((unsigned *) p.PPCData);
+				pci_config_data= (unsigned char *)ld_le32((unsigned *) (p.PPCData+8));
+                        }
+			else
+			{
+                                pci_config_address= (unsigned *) 0x80000cf8;
+                                pci_config_data= (unsigned char *) 0x80000cfc;
+                        }
+                }
+		else
+		{
+                        set_config_access_method(prep);
+                }
+
+        }
+
+	ppc_md.pcibios_fixup = prep_pcibios_fixup;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.2.7/linux/arch/ppc/kernel/prep_setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Tue May 11 08:24:32 1999
@@ -30,6 +30,9 @@
X #include <linux/blk.h>
X #include <linux/ioport.h>
X #include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/openpic.h>
X 
X #include <asm/mmu.h>
X #include <asm/processor.h>
@@ -38,12 +41,57 @@
X #include <asm/pgtable.h>
X #include <asm/ide.h>
X #include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
X 
X #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
X #include <../drivers/sound/sound_config.h>
X #include <../drivers/sound/dev_table.h>
X #endif
X 
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned long mc146818_get_rtc_time(void);
+extern int mc146818_set_rtc_time(unsigned long nowtime);
+extern unsigned long mk48t59_get_rtc_time(void);
+extern int mk48t59_set_rtc_time(unsigned long nowtime);
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+				 unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+				 unsigned char val);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+extern void prep_setup_pci_ptrs(void);
+extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
+extern char saved_command_line[256];
+
+int _prep_type;
+
+#define cached_21	(((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
+
X /* for the mac fs */
X kdev_t boot_dev;
X /* used in nasty hack for sound - see prep_setup_arch() -- Cort */
@@ -60,6 +108,9 @@
X extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
X extern int rd_image_start;	/* starting block # of image */
X #endif
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
X 
X __prep
X int
@@ -177,6 +228,13 @@
X 	outb(reg, SIO_CONFIG_RD);
X 	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
X 
+	/*
+	 * We need to set up the NvRAM access routines early as prep_init
+	 * has yet to be called
+	 */
+	ppc_md.nvram_read_val = prep_nvram_read_val;
+	ppc_md.nvram_write_val = prep_nvram_write_val;
+
X 	/* we should determine this according to what we find! -- Cort */
X 	switch ( _prep_type )
X 	{
@@ -210,9 +268,38 @@
X 		ucBoardRev=inb(0x854);
X 		ucBoardRevMaj=ucBoardRev>>5;
X 		ucBoardRevMin=ucBoardRev&0x1f;
+
+		/*
+		 * Most Radstone boards have memory mapped NvRAM
+		 */
+		if((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj<5))
+		{
+			ppc_md.nvram_read_val = prep_nvram_read_val;
+			ppc_md.nvram_write_val = prep_nvram_write_val;
+		}
+		else
+		{
+			ppc_md.nvram_read_val = rs_nvram_read_val;
+			ppc_md.nvram_write_val = rs_nvram_write_val;
+		}
X 		break;
X 	}
X 
+      /* Read in NVRAM data */ 
+      init_prep_nvram();
+       
+      /* if no bootargs, look in NVRAM */
+      if ( cmd_line[0] == '\0' ) {
+              char *bootargs;
+              bootargs = prep_nvram_get_var("bootargs");
+              if (bootargs != NULL) {
+                      strcpy(cmd_line, bootargs);
+
+                      /* again.. */
+                      strcpy(saved_command_line, cmd_line);
+              }
+      }
+
X 	printk("Boot arguments: %s\n", cmd_line);
X 	
X #ifdef CONFIG_SOUND_CS4232
@@ -262,12 +349,349 @@
X 	request_region(0x80,0x10,"dma page reg");
X 	request_region(0xc0,0x20,"dma2");
X 
+	raven_init();
+
X #ifdef CONFIG_VGA_CONSOLE
+	/* remap the VGA memory */
+	vgacon_remap_base = 0xf0000000;
+	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
X         conswitchp = &vga_con;
X #endif
X }
X 
-__initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+/*
+ * Determine the decrementer frequency from the residual data
+ * This allows for a faster boot as we do not need to calibrate the
+ * decrementer against another clock. This is important for embedded systems.
+ */
+__initfunc(void prep_res_calibrate_decr(void))
+{
+	int freq, divisor;
+
+	freq = res->VitalProductData.ProcessorBusHz;
+	divisor = 4;
+	printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems.  On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+
+__initfunc(void
+prep_calibrate_decr_handler(int            irq,
+			    void           *dev,
+			    struct pt_regs *regs))
+{
+	unsigned long freq, divisor;
+	static unsigned long t1 = 0, t2 = 0;
+	
+	if ( !t1 )
+		t1 = get_dec();
+	else if (!t2)
+	{
+		t2 = get_dec();
+		t2 = t1-t2;  /* decr's in 1/HZ */
+		t2 = t2*HZ;  /* # decrs in 1s - thus in Hz */
+		freq = t2 * 60;	/* try to make freq/1e6 an integer */
+		divisor = 60;
+		printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+		       freq, divisor,t2>>20);
+		decrementer_count = freq / HZ / divisor;
+		count_period_num = divisor;
+		count_period_den = freq / 1000000;
+		*done_ptr = 1;
+	}
+}
+
+__initfunc(void prep_calibrate_decr(void))
+{
+	unsigned long flags;
+
+
+	save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+	/* set timer to periodic mode */
+	outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+	/* set the clock to ~100 Hz */
+	outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
+	outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
+	
+	if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+	__sti();
+	while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+        restore_flags(flags);
+	free_irq( 0, NULL);
+}
+
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer. */
+__initfunc(void mk48t59_calibrate_decr(void))
+{
+	unsigned long freq, divisor;
+	unsigned long t1, t2;
+        unsigned char save_control;
+        long i;
+	unsigned char sec;
+ 
+		
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+	t1 = get_dec();
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+
+	t2 = t1 - get_dec();
+
+	freq = t2 * 60;	/* try to make freq/1e6 an integer */
+	divisor = 60;
+	printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+	       freq, divisor,t2>>20);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+void
+prep_restart(char *cmd)
+{
+        unsigned long i = 10000;
+
+
+        _disable_interrupts();
+
+        /* set exception prefix high - to the prom */
+        _nmask_and_or_msr(0, MSR_IP);
+
+        /* make sure bit 0 (reset) is a 0 */
+        outb( inb(0x92) & ~1L , 0x92 );
+        /* signal a reset to system control port A - soft reset */
+        outb( inb(0x92) | 1 , 0x92 );
+
+        while ( i != 0 ) i++;
+        panic("restart failed\n");
+}
+
+/*
+ * This function will restart a board regardless of port 92 functionality
+ */
+void
+prep_direct_restart(char *cmd)
+{
+	u32 jumpaddr=0xfff00100;
+	u32 defaultmsr=MSR_IP;
+
+	/*
+	 * This will ALWAYS work regardless of port 92
+	 * functionality
+	 */
+	_disable_interrupts();
+
+	__asm__ __volatile__("\n\
+	mtspr   26, %1  /* SRR0 */
+	mtspr   27, %0  /* SRR1 */
+	rfi"
+	:
+	: "r" (defaultmsr), "r" (jumpaddr));
+	/*
+	 * Not reached
+	 */
+}
+
+void
+prep_halt(void)
+{
+        unsigned long flags;
+	_disable_interrupts();
+	/* set exception prefix high - to the prom */
+	save_flags( flags );
+	restore_flags( flags|MSR_IP );
+	
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(0x92) & ~1L , 0x92 );
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(0x92) | 1 , 0x92 );
+                
+	while ( 1 ) ;
+	/*
+	 * Not reached
+	 */
+}
+
+void
+prep_power_off(void)
+{
+	prep_halt();
+}
+
+int prep_setup_residual(char *buffer)
+{
+        int len = 0;
+
+
+	/* PREP's without residual data will give incorrect values here */
+	len += sprintf(len+buffer, "clock\t\t: ");
+	if ( res->ResidualLength )
+		len += sprintf(len+buffer, "%ldMHz\n",
+		       (res->VitalProductData.ProcessorHz > 1024) ?
+		       res->VitalProductData.ProcessorHz>>20 :
+		       res->VitalProductData.ProcessorHz);
+	else
+		len += sprintf(len+buffer, "???\n");
+
+	return len;
+}
+
+u_int
+prep_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+void                           
+prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+        int irq;
+
+	if ( (irq = i8259_irq(0)) < 0 )
+	{
+		printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+		       regs->nip);
+		ppc_spurious_interrupts++;
+		return;
+	}
+        ppc_irq_dispatch_handler( regs, irq );
+}		
+
+__initfunc(void
+prep_init_IRQ(void))
+{
+	int i;
+
+	if (OpenPIC != NULL) {
+		for ( i = 16 ; i < 36 ; i++ )
+			irq_desc[i].ctl = &open_pic;
+		openpic_init(1);
+	}
+	
+        for ( i = 0 ; i < 16  ; i++ )
+                irq_desc[i].ctl = &i8259_pic;
+        i8259_init();
+#ifdef __SMP__
+	request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+		    0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	_insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+void
+prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	_outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+int
+prep_ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 13;
+		case 0x170: return 13;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		default:
+                        return 0;
+	}
+}
+
+ide_ioreg_t
+prep_ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0: return 0x1f0;
+		case 1: return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		default:
+                        return 0;
+	}
+}
+
+int
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+void
+prep_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+void
+prep_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+void
+prep_ide_fix_driveid(struct hd_driveid *id)
+{
+}
+
+__initfunc(void
+prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
X {
X 	ide_ioreg_t port = base;
X 	int i = 8;
@@ -277,6 +701,143 @@
X 	*p++ = base + 0x206;
X 	if (irq != NULL)
X 		*irq = 0;
+}
+#endif
+
+__initfunc(void
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+ /* make a copy of residual data */
+	if ( r3 )
+	{
+		memcpy((void *)res,(void *)(r3+KERNELBASE),
+		       sizeof(RESIDUAL));
+	}
+
+	isa_io_base = PREP_ISA_IO_BASE;
+	isa_mem_base = PREP_ISA_MEM_BASE;
+	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	/* figure out what kind of prep workstation we are */
+	if ( res->ResidualLength != 0 )
+	{
+		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+			_prep_type = _PREP_IBM;
+                else if (!strncmp(res->VitalProductData.PrintableModel,
+                                  "Radstone",8))
+                {
+                        extern char *Motherboard_map_name;
+
+                        _prep_type = _PREP_Radstone;
+                        Motherboard_map_name=
+                                res->VitalProductData.PrintableModel;
+                }
+		else
+			_prep_type = _PREP_Motorola;
+	}
+	else /* assume motorola if no residual (netboot?) */
+	{
+		_prep_type = _PREP_Motorola;
+	}
+
+	prep_setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* take care of cmd line */
+	if ( r6  && (((char *) r6) != '\0'))
+	{
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch     = prep_setup_arch;
+	ppc_md.setup_residual = prep_setup_residual;
+	ppc_md.get_cpuinfo    = prep_get_cpuinfo;
+	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+	ppc_md.init_IRQ       = prep_init_IRQ;
+	if ( !OpenPIC )
+		ppc_md.do_IRQ         = prep_do_IRQ;
+	else
+		ppc_md.do_IRQ         = chrp_do_IRQ;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = prep_restart;
+	ppc_md.power_off      = prep_power_off;
+	ppc_md.halt           = prep_halt;
+
+	ppc_md.time_init      = NULL;
+	if (_prep_type == _PREP_Radstone) {
+		/*
+		 * We require a direct restart as port 92 does not work on
+		 * all Radstone boards
+		 */
+		ppc_md.restart        = prep_direct_restart;
+		/*
+		 * The RTC device used varies according to board type
+		 */
+		if(((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj>=5)) ||
+		   (ucSystemType==RS_SYS_TYPE_PPC1a))
+		{
+			ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+			ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		}
+		else
+		{
+			ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+			ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		}
+		/*
+		 * Determine the decrementer rate from the residual data
+		 */
+		ppc_md.calibrate_decr = prep_res_calibrate_decr;
+	}
+	else if (_prep_type == _PREP_IBM) {
+		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+		ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		ppc_md.calibrate_decr = prep_calibrate_decr;
+	}
+	else {
+		ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+		ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		ppc_md.calibrate_decr = mk48t59_calibrate_decr;
+	}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = prep_ide_insw;
+        ppc_ide_md.outsw = prep_ide_outsw;
+        ppc_ide_md.default_irq = prep_ide_default_irq;
+        ppc_ide_md.default_io_base = prep_ide_default_io_base;
+        ppc_ide_md.check_region = prep_ide_check_region;
+        ppc_ide_md.request_region = prep_ide_request_region;
+        ppc_ide_md.release_region = prep_ide_release_region;
+        ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif		
+        ppc_ide_md.io_base = _IO_BASE;
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#endif
X }
X 
X #ifdef CONFIG_SOUND_MODULE
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
--- v2.2.7/linux/arch/ppc/kernel/prep_time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prep_time.c	Thu Apr 29 12:39:01 1999
@@ -22,7 +22,9 @@
X #include <asm/segment.h>
X #include <asm/io.h>
X #include <asm/processor.h>
-#include <asm/nvram.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
X 
X #include "time.h"
X 
@@ -41,133 +43,44 @@
X  * is setup at boot time to use the correct addresses.
X  * -- Cort
X  */
-/*
- * translate from mc146818 to m48t18  addresses
- */
-unsigned int clock_transl[] __prepdata = { MOTO_RTC_SECONDS,0 /* alarm */,
-		       MOTO_RTC_MINUTES,0 /* alarm */,
-		       MOTO_RTC_HOURS,0 /* alarm */,                 /*  4,5 */
-		       MOTO_RTC_DAY_OF_WEEK,
-		       MOTO_RTC_DAY_OF_MONTH,
-		       MOTO_RTC_MONTH,
-		       MOTO_RTC_YEAR,                    /* 9 */
-		       MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
-};
-
-/*
- * The following struture is used to access the MK48T18
- */
-typedef volatile struct _MK48T18 {
-	unsigned char	ucNvRAM[0x3ff8]; /* NvRAM locations */
-	unsigned char	ucControl;
-	unsigned char	ucSecond;	/* 0-59 */
-	unsigned char	ucMinute;	/* 0-59 */
-	unsigned char	ucHour;		/* 0-23 */
-	unsigned char	ucDay;		/* 1-7 */
-	unsigned char	ucDate;		/* 1-31 */
-	unsigned char	ucMonth;	/* 1-12 */
-	unsigned char	ucYear;		/* 0-99 */
-} MK48T18, *PMK48T18;
-
-/*
- * The control register contains a 5 bit calibration value plus sign
- * and read/write enable bits
- */
-#define MK48T18_CTRL_CAL_MASK	0x1f
-#define MK48T18_CTRL_CAL_SIGN	0x20
-#define MK48T18_CTRL_READ	0x40
-#define MK48T18_CTRL_WRITE	0x80
-/*
- * The STOP bit is the most significant bit of the seconds location
- */
-#define MK48T18_SEC_MASK	0x7f
-#define MK48T18_SEC_STOP	0x80
-/*
- * The day location also contains the frequency test bit which should
- * be zero for normal operation
- */
-#define MK48T18_DAY_MASK	0x07
-#define MK48T18_DAY_FT		0x40
-
-__prep
-int prep_cmos_clock_read(int addr)
-{
-	if ( _prep_type == _PREP_IBM )
-		return CMOS_READ(addr);
-	else if ( _prep_type == _PREP_Motorola )
-	{
-		outb(clock_transl[addr]>>8, NVRAM_AS1);
-		outb(clock_transl[addr], NVRAM_AS0);
-		return (inb(NVRAM_DATA));
-	}
-        else if ( _prep_type == _PREP_Radstone )
-                return CMOS_READ(addr);
-
-	printk("Unknown machine in prep_cmos_clock_read()!\n");
-	return -1;
-}
-
-__prep
-void prep_cmos_clock_write(unsigned long val, int addr)
-{
-	if ( _prep_type == _PREP_IBM )
-	{
-		CMOS_WRITE(val,addr);
-		return;
-	}
-	else if ( _prep_type == _PREP_Motorola )
-	{
-		outb(clock_transl[addr]>>8, NVRAM_AS1);
-		outb(clock_transl[addr], NVRAM_AS0);
-		outb(val,NVRAM_DATA);
-		return;
-	}
-        else if ( _prep_type == _PREP_Radstone )
-        {
-                CMOS_WRITE(val,addr);
-                return;
-        }
-
-	printk("Unknown machine in prep_cmos_clock_write()!\n");
-}
X 
X /*
X  * Set the hardware clock. -- Cort
X  */
X __prep
-int prep_set_rtc_time(unsigned long nowtime)
+int mc146818_set_rtc_time(unsigned long nowtime)
X {
X 	unsigned char save_control, save_freq_select;
X 	struct rtc_time tm;
X 
X 	to_tm(nowtime, &tm);
X 
-	save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
-	prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	/* tell the clock it's being set */
+	save_control = CMOS_READ(RTC_CONTROL);
X 	
-	prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-        tm.tm_year -= 1900;
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	
+	/* stop and reset prescaler */
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	
+        tm.tm_year = (tm.tm_year - 1900) % 100;
X 	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
X 		BIN_TO_BCD(tm.tm_sec);
X 		BIN_TO_BCD(tm.tm_min);
X 		BIN_TO_BCD(tm.tm_hour);
X 		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_wday);
X 		BIN_TO_BCD(tm.tm_mday);
X 		BIN_TO_BCD(tm.tm_year);
X 	}
-	prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
-	prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
-	prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
-	prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
-	prep_cmos_clock_write(tm.tm_wday+1,RTC_DAY_OF_WEEK);
-	prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
-	prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
-
+	CMOS_WRITE(tm.tm_sec,  RTC_SECONDS);
+	CMOS_WRITE(tm.tm_min,  RTC_MINUTES);
+	CMOS_WRITE(tm.tm_hour, RTC_HOURS);
+	CMOS_WRITE(tm.tm_mon,  RTC_MONTH);
+	CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
+	CMOS_WRITE(tm.tm_year, RTC_YEAR);
+	
X 	/* The following flags have to be released exactly in this order,
X 	 * otherwise the DS12887 (popular MC146818A clone with integrated
X 	 * battery and quartz) will not reset the oscillator and will not
@@ -175,52 +88,14 @@
X 	 * the Dallas Semiconductor data sheets, but who believes data
X 	 * sheets anyway ...                           -- Markus Kuhn
X 	 */
-	prep_cmos_clock_write(save_control, RTC_CONTROL);
-	prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+	CMOS_WRITE(save_control,     RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
X 
-	/*
-	 * Radstone Technology PPC1a boards use an MK48T18 device
-	 * as the "master" RTC but also have a DS1287 equivalent incorporated
-	 * into the PCI-ISA bridge device. The DS1287 is initialised by the boot
-	 * firmware to reflect the value held in the MK48T18 and thus the
-	 * time may be read from this device both here and in the rtc driver.
-	 * Whenever we set the time, however, if it is to be preserved across
-	 * boots we must also update the "master" RTC.
-	 */
-	if((_prep_type==_PREP_Radstone) && (ucSystemType==RS_SYS_TYPE_PPC1a))
-	{
-		PMK48T18 pMk48t18=(PMK48T18)(_ISA_MEM_BASE+0x00800000);
-
-		/*
-		 * Set the write enable bit
-		 */
-		pMk48t18->ucControl|=MK48T18_CTRL_WRITE;
-		eieio();
-		/*
-		 * Update the clock
-		 */
-		pMk48t18->ucSecond=tm.tm_sec;
-		pMk48t18->ucMinute=tm.tm_min;
-		pMk48t18->ucHour=tm.tm_hour;
-		pMk48t18->ucMonth=tm.tm_mon;
-		pMk48t18->ucDay=tm.tm_wday+1;
-		pMk48t18->ucDate=tm.tm_mday;
-		pMk48t18->ucYear=tm.tm_year;
-
-		eieio();
-		/*
-		 * Clear the write enable bit
-		 */
-		pMk48t18->ucControl&=~MK48T18_CTRL_WRITE;
-	}
-
-	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
-		time_state = TIME_OK;
X 	return 0;
X }
X 
X __prep
-unsigned long prep_get_rtc_time(void)
+unsigned long mc146818_get_rtc_time(void)
X {
X 	unsigned int year, mon, day, hour, min, sec;
X 	int i;
@@ -232,29 +107,123 @@
X 	 */
X 	/* read RTC exactly on falling edge of update flag */
X 	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
X 			break;
X 	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
X 			break;
X 	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		sec = prep_cmos_clock_read(RTC_SECONDS);
-		min = prep_cmos_clock_read(RTC_MINUTES);
-		hour = prep_cmos_clock_read(RTC_HOURS);
-		day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
-		mon = prep_cmos_clock_read(RTC_MONTH);
-		year = prep_cmos_clock_read(RTC_YEAR);
-	} while (sec != prep_cmos_clock_read(RTC_SECONDS));
-	if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
-	    BCD_TO_BIN(sec);
-	    BCD_TO_BIN(min);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
+		sec = CMOS_READ(RTC_SECONDS);
+		min = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+	} while (sec != CMOS_READ(RTC_SECONDS));
+	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+	    || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
X 	if ((year += 1900) < 1970)
X 		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+__prep
+int mk48t59_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control;
+	struct rtc_time tm;
+
+
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being written */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_WRITE));
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
+	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
+	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
+	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
+	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
+	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
+	
+	/* Turn off the write bit. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+	unsigned char save_control;
+	unsigned int year, mon, day, hour, min, sec;
+	int i;
+
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+		
+	/* Wait until the seconds value changes, then read the value. */
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+
+	/* Set the register to read the value. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_READ));
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
+	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
+	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
+	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
+	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
+
+	/* Let the time values change again. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
X 	return mktime(year, mon, day, hour, min, sec);
X }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.2.7/linux/arch/ppc/kernel/process.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/process.c	Tue May 11 08:24:32 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: process.c,v 1.75 1999/02/12 07:06:29 cort Exp $
+ * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
X  *
X  *  linux/arch/ppc/kernel/process.c
X  *
@@ -43,10 +43,7 @@
X #include <asm/prom.h>
X 
X int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
-void switch_to(struct task_struct *, struct task_struct *);
-
X extern unsigned long _get_SP(void);
-extern spinlock_t scheduler_lock;
X 
X struct task_struct *last_task_used_math = NULL;
X static struct vm_area_struct init_mmap = INIT_MMAP;
@@ -77,17 +74,25 @@
X int
X dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
X {
-#ifdef __SMP__
-	if ( regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else
-	if (last_task_used_math == current)
-		giveup_fpu();
-#endif	
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
X 	memcpy(fpregs, ¤t->tss.fpr[0], sizeof(*fpregs));
X 	return 1;
X }
X 
+void
+enable_kernel_fp(void)
+{
+#ifdef __SMP__
+	if (current->tss.regs && (current->tss.regs->msr & MSR_FP))
+		giveup_fpu(current);
+	else
+		giveup_fpu(NULL);	/* just enables FP for kernel */
+#else
+	giveup_fpu(last_task_used_math);
+#endif /* __SMP__ */
+}
+
X /* check to make sure the kernel stack is healthy */
X int check_stack(struct task_struct *tsk)
X {
@@ -152,7 +157,8 @@
X }
X 
X void
-switch_to(struct task_struct *prev, struct task_struct *new)
+_switch_to(struct task_struct *prev, struct task_struct *new,
+	  struct task_struct **last)
X {
X 	struct thread_struct *new_tss, *old_tss;
X 	int s = _disable_interrupts();
@@ -162,10 +168,10 @@
X #endif
X 
X #ifdef SHOW_TASK_SWITCHES
-	printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n",
+	printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
X 	       prev->comm,prev->pid,
X 	       new->comm,new->pid,new->tss.regs->nip,new->processor,
-	       scheduler_lock.lock,new->fs->root,prev->fs->root);
+	       new->fs->root,prev->fs->root);
X #endif
X #ifdef __SMP__
X 	/* avoid complexity of lazy save/restore of fpu
@@ -173,18 +179,19 @@
X 	 * this task used the fpu during the last quantum.
X 	 * 
X 	 * If it tries to use the fpu again, it'll trap and
-	 * reload its fp regs.
+	 * reload its fp regs.  So we don't have to do a restore
+	 * every switch, just a save.
X 	 *  -- Cort
X 	 */
-	if ( prev->tss.regs->msr & MSR_FP )
-		smp_giveup_fpu(prev);
+	if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP))
+		giveup_fpu(prev);
X 
X 	prev->last_processor = prev->processor;
X 	current_set[smp_processor_id()] = new;
X #endif /* __SMP__ */
X 	new_tss = &new->tss;
X 	old_tss = ¤t->tss;
-	_switch(old_tss, new_tss, new->mm->context);
+	*last = _switch(old_tss, new_tss, new->mm->context);
X 	_enable_interrupts(s);
X }
X 
@@ -237,7 +244,12 @@
X 
X 	printk("Instruction DUMP:");
X 	for(i = -3; i < 6; i++)
-		printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+	{
+		unsigned long p;
+		if (__get_user( p, &pc[i] ))
+			break;
+		printk("%c%08lx%c",i?' ':'<',p,i?' ':'>');
+	}
X 	printk("\n");
X }
X 
@@ -265,8 +277,12 @@
X copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
X 	    struct task_struct * p, struct pt_regs * regs)
X {
-	struct pt_regs * childregs;
-	
+	struct pt_regs * childregs, *kregs;
+#ifdef __SMP__
+	extern void ret_from_smpfork(void);
+#else
+	extern void ret_from_syscall(void);
+#endif
X 	/* Copy registers */
X 	childregs = ((struct pt_regs *)
X 		     ((unsigned long)p + sizeof(union task_union)
@@ -275,8 +291,19 @@
X 	if ((childregs->msr & MSR_PR) == 0)
X 		childregs->gpr[2] = (unsigned long) p;	/* `current' in new task */
X 	childregs->gpr[3] = 0;  /* Result from fork() */
+	p->tss.regs = childregs;
X 	p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
-	p->tss.regs = childregs;	
+	p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
+	kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD);
+#ifdef __SMP__
+	kregs->nip = (unsigned long)ret_from_smpfork;
+#else	
+	kregs->nip = (unsigned long)ret_from_syscall;
+#endif	
+	kregs->msr = MSR_KERNEL;
+	kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
+	kregs->gpr[2] = (unsigned long)p;
+	
X 	if (usp >= (unsigned long) regs) {
X 		/* Stack is in kernel space - must adjust */
X 		childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -290,21 +317,14 @@
X 	 * copy fpu info - assume lazy fpu switch now always
X 	 *  -- Cort
X 	 */
-#ifdef __SMP__
-	if ( regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else	
-	if ( last_task_used_math == current )
-		giveup_fpu();
-#endif	  
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
X 
X 	memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr));
X 	p->tss.fpscr = current->tss.fpscr;
X 	childregs->msr &= ~MSR_FP;
X 
X #ifdef __SMP__
-	if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
-		p->tss.smp_fork_ret = 1;
X 	p->last_processor = NO_PROC_ID;
X #endif /* __SMP__ */
X 	return 0;
@@ -371,11 +391,6 @@
X 	int res;
X 	lock_kernel();
X 	res = do_fork(clone_flags, regs->gpr[1], regs);
-	/*
-	 * only parent returns here, child returns to either
-	 * syscall_ret_1() or kernel_thread()
-	 * -- Cort
-	 */
X #ifdef __SMP__
X 	/* When we clone the idle task we keep the same pid but
X 	 * the return value of 0 for both causes problems.
@@ -395,7 +410,6 @@
X 	int res;
X 	
X 	res = do_fork(SIGCHLD, regs->gpr[1], regs);
-	/* only parent returns here */
X #ifdef __SMP__
X 	/* When we clone the idle task we keep the same pid but
X 	 * the return value of 0 for both causes problems.
@@ -424,13 +438,8 @@
X 	error = PTR_ERR(filename);
X 	if (IS_ERR(filename))
X 		goto out;
-#ifdef __SMP__	  
-	if ( regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else	  
-	if ( last_task_used_math == current )
-		giveup_fpu();
-#endif	
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
X 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
X 	putname(filename);
X out:
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.2.7/linux/arch/ppc/kernel/prom.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prom.c	Tue May 11 08:24:32 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: prom.c,v 1.50 1999/03/16 10:40:34 cort Exp $
+ * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
X  *
X  * Procedures for interfacing to the Open Firmware PROM on
X  * Power Macintosh computers.
@@ -16,6 +16,7 @@
X #include <linux/string.h>
X #include <linux/init.h>
X #include <linux/version.h>
+#include <asm/spinlock.h>
X #include <asm/prom.h>
X #include <asm/page.h>
X #include <asm/processor.h>
@@ -263,9 +264,11 @@
X void
X prom_init(int r3, int r4, prom_entry pp)
X {
+#ifdef CONFIG_SMP	
X 	int cpu = 0, i;
X 	phandle node;
X 	char type[16], *path;
+#endif	
X 	unsigned long mem;
X 	ihandle prom_rtas;
X 	unsigned long offset = reloc_offset();
@@ -454,7 +457,7 @@
X 	 * a holding pattern controlled by the kernel (not OF) before
X 	 * we destroy the OF.
X 	 *
-	 * This used a chunk of high memory, puts some holding pattern
+	 * This uses a chunk of high memory, puts some holding pattern
X 	 * code there and sends the other processors off to there until
X 	 * smp_boot_cpus tells them to do something.  We do that by using
X 	 * physical address 0x0.  The holding pattern checks that address
@@ -1141,7 +1144,7 @@
X 	if (cp == NULL)
X 		return 0;
X 	while (cplen > 0) {
-		if (strcasecmp(cp, compat) == 0)
+		if (strncasecmp(cp, compat, strlen(compat)) == 0)
X 			return 1;
X 		l = strlen(cp) + 1;
X 		cp += l;
@@ -1277,6 +1280,8 @@
X }
X #endif
X 
+spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;
+
X /* this can be called after setup -- Cort */
X __openfirmware
X int
@@ -1307,7 +1312,9 @@
X 	for (i = 0; i < nargs; ++i)
X 		u.words[i+3] = va_arg(list, unsigned long);
X 	va_end(list);
+	spin_lock(&rtas_lock);
X 	enter_rtas((void *)__pa(&u));
+	spin_unlock(&rtas_lock);
X 	if (nret > 1 && outputs != NULL)
X 		for (i = 0; i < nret-1; ++i)
X 			outputs[i] = u.words[i+nargs+4];
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.2.7/linux/arch/ppc/kernel/ptrace.c	Thu Dec 31 10:28:59 1998
+++ linux/arch/ppc/kernel/ptrace.c	Thu Apr 29 12:39:01 1999
@@ -392,14 +392,8 @@
X 				tmp = get_reg(child, addr);
X 			}
X 			else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
-#ifdef __SMP__
-				if (child->tss.regs->msr & MSR_FP )
-					smp_giveup_fpu(child);
-#else			  
-			  /* only current can be last task to use math on SMP */
-				if (last_task_used_math == child)
-					giveup_fpu();
-#endif				
+				if (child->tss.regs->msr & MSR_FP)
+					giveup_fpu(child);
X 				tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
X 			}
X 			else
@@ -433,13 +427,8 @@
X 				goto out;
X 			}
X 			if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
-#ifndef __SMP__
-				if (last_task_used_math == child)
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 11'
echo 'File patch-2.2.8 is continued in part 12'
echo 12 > _shar_seq_.tmp
#!/bin/sh
# this is part 12 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 12; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
-					giveup_fpu();
-#else	
-				if (child->tss.regs->msr & MSR_FP )
-					smp_giveup_fpu(child);
-#endif				
+				if (child->tss.regs->msr & MSR_FP)
+					giveup_fpu(child);
X 				((long *)child->tss.fpr)[addr - PT_FPR0] = data;
X 				ret = 0;
X 				goto out;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.2.7/linux/arch/ppc/kernel/setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/setup.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: setup.c,v 1.130 1999/03/11 01:45:15 cort Exp $
+ * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $
X  * Common prep/pmac/chrp boot and setup code.
X  */
X 
@@ -30,31 +30,62 @@
X #include <asm/8xx_immap.h>
X #endif
X #include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
X 
-/* APUS defs */
-extern unsigned long m68k_machtype;
-extern int parse_bootinfo(const struct bi_record *);
-extern char _end[];
-#ifdef CONFIG_APUS
-extern struct mem_info ramdisk;
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-#endif
-/* END APUS defs */
+extern void pmac_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
+extern void chrp_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
+extern void prep_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
+extern void mbx_init(unsigned long r3,
+		     unsigned long r4,
+		     unsigned long r5,
+		     unsigned long r6,
+		     unsigned long r7);
+
+extern void apus_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
X 
X extern boot_infos_t *boot_infos;
X extern char cmd_line[512];
X char saved_command_line[256];
X unsigned char aux_device_present;
X 
-#if !defined(CONFIG_MACH_SPECIFIC)
+struct ide_machdep_calls ppc_ide_md;
+
X unsigned long ISA_DMA_THRESHOLD;
X unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
-int _machine;
-/* if we have openfirmware */
-unsigned long have_of;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+
+/* Temporary hacks until machdep.h is fully done. */
+int _machine = 0;
+/* do we have OF? */
+int have_of = 0;
+int is_prep = 0;
+int is_chrp = 0;
+/* For MTX/MVME boards.. with Raven/Falcon Chipset
+      Real close to CHRP, but boot like PReP (via PPCbug)
+      There's probably a nicer way to do this.. --Troy */
+int is_powerplus = 0;
+
+struct machdep_calls ppc_md;
+
X 
X /* copy of the residual data */
X #ifndef CONFIG_MBX
@@ -65,15 +96,6 @@
X 
X RESIDUAL *res = (RESIDUAL *)&__res;
X 
-int _prep_type;
-/*
- * This is used to identify the board type from a given PReP board
- * vendor. Board revision is also made available.
- */
-unsigned char ucSystemType;
-unsigned char ucBoardRev;
-unsigned char ucBoardRevMaj, ucBoardRevMin;
-
X /*
X  * Perhaps we can put the pmac screen_info[] here
X  * on pmac as well so we don't need the ifdef's.
@@ -122,164 +144,28 @@
X };
X #endif /* CONFIG_MBX */
X 
-/* cmd is ignored for now... */
X void machine_restart(char *cmd)
X {
-#ifndef CONFIG_MBX
-	unsigned long flags;
-	struct adb_request req;
-
-	switch(_machine)
-	{
-	case _MACH_Pmac:
-		switch (adb_hardware) {
-		case ADB_VIACUDA:
-			cuda_request(&req, NULL, 2, CUDA_PACKET,
-				     CUDA_RESET_SYSTEM);
-			for (;;)
-				cuda_poll();
-			break;
-		case ADB_VIAPMU:
-			pmu_restart();
-			break;
-		default:
-		}
-		break;
-
-	case _MACH_chrp:
-#if 0		/* RTAS doesn't seem to work on Longtrail.
-		   For now, do it the same way as the PReP. */
-	        /*err = call_rtas("system-reboot", 0, 1, NULL);
-		  printk("RTAS system-reboot returned %d\n", err);
-		  for (;;);*/
-		
-		{
-			extern unsigned int rtas_entry, rtas_data, rtas_size;
-			unsigned long status, value;
-			printk("rtas_ent`ry: %08x rtas_data: %08x rtas_size: %08x\n",
-			       rtas_entry,rtas_data,rtas_size);
-		}
-#endif
-	case _MACH_prep:
-		_disable_interrupts();
-                /* set exception prefix high - to the prom */
-                save_flags( flags );
-                restore_flags( flags|MSR_IP );
-                
-                /* make sure bit 0 (reset) is a 0 */
-                outb( inb(0x92) & ~1L , 0x92 );
-                /* signal a reset to system control port A - soft reset */
-                outb( inb(0x92) | 1 , 0x92 );
-                
-                while ( 1 ) ;
-                break;
-		/*
-		 * Not reached
-		 */
-	case _MACH_apus:
-		cli();
-
-		APUS_WRITE(APUS_REG_LOCK, 
-			   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
-		APUS_WRITE(APUS_REG_LOCK, 
-			   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
-		APUS_WRITE(APUS_REG_LOCK, 
-			   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
-		APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
-		APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
-		for(;;);
-		break;
-	}
-#else /* CONFIG_MBX */
-        extern void __clear_msr_me(void);
-        __volatile__ unsigned char dummy;
-	
-        cli();
-        ((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;
-        __clear_msr_me();
-        dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
- 
-	printk("Restart failed\n");
-	while(1);
-#endif /* CONFIG_MBX */
+	ppc_md.restart(cmd);
X }
-
+  
X void machine_power_off(void)
X {
-#ifndef CONFIG_MBX	
-	struct adb_request req;
-#if 0	
-	int err;
-#endif	
-
-	switch (_machine) {
-	case _MACH_Pmac:
-		switch (adb_hardware) {
-		case ADB_VIACUDA:
-			cuda_request(&req, NULL, 2, CUDA_PACKET,
-				     CUDA_POWERDOWN);
-			for (;;)
-				cuda_poll();
-			break;
-		case ADB_VIAPMU:
-			pmu_shutdown();
-			break;
-		default:
-		}
-		break;
-
-	case _MACH_chrp:
-#if 0		/* RTAS doesn't seem to work on Longtrail.
-		   For now, do it the same way as the PReP. */
-		err = call_rtas("power-off", 2, 1, NULL, 0, 0);
-		printk("RTAS system-reboot returned %d\n", err);
-		for (;;);
-#endif
-
-	case _MACH_prep:
-		machine_restart(NULL);
-	case _MACH_apus:
-		for (;;);
-	}
-	for (;;);
-#else /* CONFIG_MBX */
-	machine_halt();
-#endif /* CONFIG_MBX */
+	ppc_md.power_off();
X }
-
+  
X void machine_halt(void)
X {
-	if ( _machine == _MACH_Pmac )
-	{
-		machine_power_off();
-	}
-	else /* prep, chrp or apus */
-		machine_restart(NULL);
+	ppc_md.halt();
X }
-
+  
X #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
X void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
X {
-#if !defined(CONFIG_MBX) && !defined(CONFIG_APUS)
-	switch (_machine) {
-#if defined(CONFIG_BLK_DEV_IDE_PMAC)
-	case _MACH_Pmac:
-	  	pmac_ide_init_hwif_ports(p,base,irq);
-		break;
-#endif		
-	case _MACH_chrp:
-		chrp_ide_init_hwif_ports(p,base,irq);
-		break;
-	case _MACH_prep:
-		prep_ide_init_hwif_ports(p,base,irq);
-		break;
+	if (ppc_ide_md.ide_init_hwif != NULL) {
+		ppc_ide_md.ide_init_hwif(p, base, irq);
X 	}
-#endif
-#if defined(CONFIG_MBX)
-	mbx_ide_init_hwif_ports(p,base,irq);
-#endif	
X }
-EXPORT_SYMBOL(ide_init_hwif_ports);
X #endif
X 
X unsigned long cpu_temp(void)
@@ -313,10 +199,6 @@
X 
X int get_cpuinfo(char *buffer)
X {
-	extern int pmac_get_cpuinfo(char *);
-	extern int chrp_get_cpuinfo(char *);	
-	extern int prep_get_cpuinfo(char *);
-	extern int apus_get_cpuinfo(char *);
X 	unsigned long len = 0;
X 	unsigned long bogosum = 0;
X 	unsigned long i;
@@ -380,7 +262,6 @@
X 			break;
X 		}
X 		
-#ifndef CONFIG_MBX
X 		/*
X 		 * Assume here that all clock rates are the same in a
X 		 * smp system.  -- Cort
@@ -397,33 +278,11 @@
X 			len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
X 				       *fp / 1000000);
X 		}
-		
-		/* PREP's without residual data for some reason will give
-		   incorrect values here */
-		if ( is_prep )
-		{
-			len += sprintf(len+buffer, "clock\t\t: ");
-			if ( res->ResidualLength )
-				len += sprintf(len+buffer, "%ldMHz\n",
-				       (res->VitalProductData.ProcessorHz > 1024) ?
-				       res->VitalProductData.ProcessorHz>>20 :
-				       res->VitalProductData.ProcessorHz);
-			else
-				len += sprintf(len+buffer, "???\n");
-		}
-#else /* CONFIG_MBX */
+
+		if (ppc_md.setup_residual != NULL)
X 		{
-			bd_t	*bp;
-			extern	RESIDUAL *res;
-			
-			bp = (bd_t *)res;
-			
-			len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
-				      "bus clock\t: %dMHz\n",
-				      bp->bi_intfreq /*/ 1000000*/,
-				      bp->bi_busfreq /*/ 1000000*/);
+			len += ppc_md.setup_residual(buffer + len);
X 		}
-#endif /* CONFIG_MBX */		
X 		
X 		len += sprintf(len+buffer, "revision\t: %ld.%ld\n",
X 			       (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
@@ -438,8 +297,8 @@
X 	if ( i )
X 		len += sprintf(buffer+len, "\n");
X 	len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
-	       (bogosum+2500)/500000,
-	       (bogosum+2500)/5000 % 100);
+		       (bogosum+2500)/500000,
+		       (bogosum+2500)/5000 % 100);
X #endif /* __SMP__ */
X 
X 	/*
@@ -455,27 +314,14 @@
X 			       zero_cache_hits,zero_cache_calls,
X 			       /* : 1 below is so we don't div by zero */
X 			       (zero_cache_hits*100) /
-			            ((zero_cache_calls)?zero_cache_calls:1));
+			       ((zero_cache_calls)?zero_cache_calls:1));
X 	}
X 
-#ifndef CONFIG_MBX
-	switch (_machine)
+	if (ppc_md.get_cpuinfo != NULL)
X 	{
-	case _MACH_Pmac:
-		len += pmac_get_cpuinfo(buffer+len);
-		break;
-	case _MACH_prep:
- len += prep_get_cpuinfo(buffer+len);
-		break;
-	case _MACH_chrp:
-		len += chrp_get_cpuinfo(buffer+len);
-		break;
-	case _MACH_apus:
-		/* Not much point in printing m68k info when it is not
-                   used. */
-		break;
+		len += ppc_md.get_cpuinfo(buffer+len);
X 	}
-#endif /* ndef CONFIG_MBX */	
+
X 	return len;
X }
X 
@@ -487,25 +333,22 @@
X identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
X 		 unsigned long r6, unsigned long r7)
X {
-	extern void setup_pci_ptrs(void);
X 	
X #ifdef __SMP__
X 	if ( first_cpu_booted ) return 0;
X #endif /* __SMP__ */
X 	
-#ifndef CONFIG_MBX
X #ifndef CONFIG_MACH_SPECIFIC
X 	/* boot loader will tell us if we're APUS */
X 	if ( r3 == 0x61707573 )
X 	{
X 		_machine = _MACH_apus;
-		have_of = 0;
X 		r3 = 0;
X 	}
X 	/* prep boot loader tells us if we're prep or not */
X 	else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) {
X 		_machine = _MACH_prep;
-		have_of = 0;
+		is_prep = 1;
X 	} else {
X 		char *model;
X 
@@ -516,19 +359,49 @@
X 		/* ask the OF info if we're a chrp or pmac */
X 		model = get_property(find_path_device("/"), "device_type", NULL);
X 		if ( model && !strncmp("chrp",model,4) )
+		{
X 			_machine = _MACH_chrp;
+			is_chrp = 1;
+		}
X 		else
X 		{
X 			model = get_property(find_path_device("/"),
X 					     "model", NULL);
X 			if ( model && !strncmp(model, "IBM", 3))
+			{
X 				_machine = _MACH_chrp;
+				is_chrp = 1;
+			}
X 			else
+			{
X 				_machine = _MACH_Pmac;
+				is_prep = 1;
+			}
X 		}
X 
X 	}
-#endif /* CONFIG_MACH_SPECIFIC */		
+#else /* CONFIG_MACH_SPECIFIC */
+
+#ifdef CONFIG_PREP
+	_machine = _MACH_prep;
+	is_prep  = 1;
+#elif defined(CONFIG_CHRP)
+	_machine = _MACH_chrp;
+	is_chrp  = 1;
+	have_of  = 1;
+#elif defined(CONFIG_PMAC)
+	_machine = _MACH_Pmac;
+	have_of  = 1;
+#elif defined(CONFIG_MBX)
+	_machine = _MACH_mbx;
+#elif defined(CONFIG_FADS)
+	_machine = _MACH_fads;
+#elif defined(CONFIG_APUS)
+	_machine = _MACH_apus;
+#else
+#error "Machine not defined correctly"
+#endif /* CONFIG_APUS */
+#endif /* CONFIG_MACH_SPECIFIC */
X 
X 	if ( have_of )
X 	{
@@ -587,138 +460,31 @@
X 		cmd_line[sizeof(cmd_line) - 1] = 0;
X 	}
X 
-
X 	switch (_machine)
X 	{
X 	case _MACH_Pmac:
-		setup_pci_ptrs();
-		/* isa_io_base gets set in pmac_find_bridges */
-		isa_mem_base = PMAC_ISA_MEM_BASE;
-		pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = ~0L;
-		DMA_MODE_READ = 1;
-		DMA_MODE_WRITE = 2;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+                pmac_init(r3, r4, r5, r6, r7);
X 		break;
X 	case _MACH_prep:
-		/* make a copy of residual data */
-		if ( r3 )
-			memcpy((void *)res,(void *)(r3+KERNELBASE),
-			       sizeof(RESIDUAL));
-		isa_io_base = PREP_ISA_IO_BASE;
-		isa_mem_base = PREP_ISA_MEM_BASE;
-		pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = 0x00ffffff;
-		DMA_MODE_READ = 0x44;
-		DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
-		/* figure out what kind of prep workstation we are */
-		if ( res->ResidualLength != 0 )
-		{
-			if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
-				_prep_type = _PREP_IBM;
-			else if (!strncmp(res->VitalProductData.PrintableModel,
-					  "Radstone",8))
-			{
-				extern char *Motherboard_map_name;
-
-				_prep_type = _PREP_Radstone;
-				Motherboard_map_name=
-					res->VitalProductData.PrintableModel;
-			}
-			else
-				_prep_type = _PREP_Motorola;
-		}
-		else /* assume motorola if no residual (netboot?) */
-			_prep_type = _PREP_Motorola;
-		setup_pci_ptrs();
-#ifdef CONFIG_BLK_DEV_INITRD
-		/* take care of initrd if we have one */
-		if ( r4 )
-		{
-			initrd_start = r4 + KERNELBASE;
-			initrd_end = r5 + KERNELBASE;
-		}
-#endif /* CONFIG_BLK_DEV_INITRD */
-		/* take care of cmd line */
-		if ( r6 )
-		{
-			*(char *)(r7+KERNELBASE) = 0;
-			strcpy(cmd_line, (char *)(r6+KERNELBASE));
-		}
+                prep_init(r3, r4, r5, r6, r7);
X 		break;
X 	case _MACH_chrp:
-		setup_pci_ptrs();
-#ifdef CONFIG_BLK_DEV_INITRD
-		/* take care of initrd if we have one */
-		if ( r3 )
-		{
-			initrd_start = r3 + KERNELBASE;
-			initrd_end = r3 + r4 + KERNELBASE;
-		}
-#endif /* CONFIG_BLK_DEV_INITRD */
-		/* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = ~0L;
-		DMA_MODE_READ = 0x44;
-		DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+                chrp_init(r3, r4, r5, r6, r7);
X 		break;
-#ifdef CONFIG_APUS		
+#ifdef CONFIG_APUS
X 	case _MACH_apus:
-		/* Parse bootinfo. The bootinfo is located right after
-                   the kernel bss */
-		parse_bootinfo((const struct bi_record *)&_end);
-#ifdef CONFIG_BLK_DEV_INITRD
-		/* Take care of initrd if we have one. Use data from
-		   bootinfo to avoid the need to initialize PPC
-		   registers when kernel is booted via a PPC reset. */
-		if ( ramdisk.addr ) {
-			initrd_start = (unsigned long) __va(ramdisk.addr);
-			initrd_end = (unsigned long) 
-				__va(ramdisk.size + ramdisk.addr);
-		}
-		/* Make sure code below is not executed. */
-		r4 = 0;
-		r6 = 0;
-#endif /* CONFIG_BLK_DEV_INITRD */
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = 0x00ffffff;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+                apus_init(r3, r4, r5, r6, r7);
X 		break;
X #endif
+#ifdef CONFIG_MBX
+        case _MACH_mbx:
+                mbx_init(r3, r4, r5, r6, r7);
+                break;
+#endif
X 	default:
X 		printk("Unknown machine type in identify_machine!\n");
X 	}
X 
-#else /* CONFIG_MBX */
-
-	if ( r3 )
-		memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-	
-#ifdef CONFIG_PCI
-	setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-	/* take care of cmd line */
-	if ( r6 )
-	{
-		
-		*(char *)(r7+KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6+KERNELBASE));
-	}
-#endif /* CONFIG_MBX */
-
X 	/* Check for nobats option (used in mapin_ram). */
X 	if (strstr(cmd_line, "nobats")) {
X 		extern int __map_without_bats;
@@ -740,14 +506,17 @@
X 	}
X }
X 
+__initfunc(void
+	   ppc_init(void))
+{
+	if (ppc_md.init != NULL) {
+		ppc_md.init();
+	}
+}
+
X __initfunc(void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p))
+			   unsigned long * memory_start_p, unsigned long * memory_end_p))
X {
-	extern void pmac_setup_arch(unsigned long *, unsigned long *);
-	extern void chrp_setup_arch(unsigned long *, unsigned long *);
-	extern void prep_setup_arch(unsigned long *, unsigned long *);
-	extern void mbx_setup_arch(unsigned long *, unsigned long *);
-	extern void apus_setup_arch(unsigned long *, unsigned long *);
X 	extern int panic_timeout;
X 	extern char _etext[], _edata[];
X 	extern char *klimit;
@@ -776,27 +545,113 @@
X 	*memory_start_p = find_available_memory();
X 	*memory_end_p = (unsigned long) end_of_DRAM;
X 
-#ifdef CONFIG_MBX
-	mbx_setup_arch(memory_start_p,memory_end_p);
-#else /* CONFIG_MBX */	
-	switch (_machine) {
-	case _MACH_Pmac:
-		pmac_setup_arch(memory_start_p, memory_end_p);
-		break;
-	case _MACH_prep:
- prep_setup_arch(memory_start_p, memory_end_p);
-		break;
-	case _MACH_chrp:
- chrp_setup_arch(memory_start_p, memory_end_p);
-		break;
-#ifdef CONFIG_APUS		
-	case _MACH_apus:
-		m68k_machtype = MACH_AMIGA;
-		apus_setup_arch(memory_start_p,memory_end_p);
-		break;
-#endif
-	default:
-		printk("Unknown machine %d in setup_arch()\n", _machine);
-	}
-#endif /* CONFIG_MBX */	
+	ppc_md.setup_arch(memory_start_p, memory_end_p);
+}
+
+void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
+{
+        int i;
+	unsigned short *stringcast;
+
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (unsigned short *)&id->serial_no[0];
+	for (i=0; i<(20/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (unsigned short *)&id->fw_rev[0];
+	for (i=0; i<(8/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (unsigned short *)&id->model[0];
+	for (i=0; i<(40/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	id->word69         = __le16_to_cpu(id->word69);
+	id->word70         = __le16_to_cpu(id->word70);
+	id->word71         = __le16_to_cpu(id->word71);
+	id->word72         = __le16_to_cpu(id->word72);
+	id->word73         = __le16_to_cpu(id->word73);
+	id->word74         = __le16_to_cpu(id->word74);
+	id->word75         = __le16_to_cpu(id->word75);
+	id->word76         = __le16_to_cpu(id->word76);
+	id->word77         = __le16_to_cpu(id->word77);
+	id->word78         = __le16_to_cpu(id->word78);
+	id->word79         = __le16_to_cpu(id->word79);
+	id->word80         = __le16_to_cpu(id->word80);
+	id->word81         = __le16_to_cpu(id->word81);
+	id->command_sets   = __le16_to_cpu(id->command_sets);
+	id->word83         = __le16_to_cpu(id->word83);
+	id->word84         = __le16_to_cpu(id->word84);
+	id->word85         = __le16_to_cpu(id->word85);
+	id->word86         = __le16_to_cpu(id->word86);
+	id->word87         = __le16_to_cpu(id->word87);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->word91         = __le16_to_cpu(id->word91);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->word93         = __le16_to_cpu(id->word93);
+	id->word94         = __le16_to_cpu(id->word94);
+	id->word95         = __le16_to_cpu(id->word95);
+	id->word96         = __le16_to_cpu(id->word96);
+	id->word97         = __le16_to_cpu(id->word97);
+	id->word98         = __le16_to_cpu(id->word98);
+	id->word99         = __le16_to_cpu(id->word99);
+	id->word100        = __le16_to_cpu(id->word100);
+	id->word101        = __le16_to_cpu(id->word101);
+	id->word102        = __le16_to_cpu(id->word102);
+	id->word103        = __le16_to_cpu(id->word103);
+	id->word104        = __le16_to_cpu(id->word104);
+	id->word105        = __le16_to_cpu(id->word105);
+	id->word106        = __le16_to_cpu(id->word106);
+	id->word107        = __le16_to_cpu(id->word107);
+	id->word108        = __le16_to_cpu(id->word108);
+	id->word109        = __le16_to_cpu(id->word109);
+	id->word110        = __le16_to_cpu(id->word110);
+	id->word111        = __le16_to_cpu(id->word111);
+	id->word112        = __le16_to_cpu(id->word112);
+	id->word113        = __le16_to_cpu(id->word113);
+	id->word114        = __le16_to_cpu(id->word114);
+	id->word115        = __le16_to_cpu(id->word115);
+	id->word116        = __le16_to_cpu(id->word116);
+	id->word117        = __le16_to_cpu(id->word117);
+	id->word118        = __le16_to_cpu(id->word118);
+	id->word119        = __le16_to_cpu(id->word119);
+	id->word120        = __le16_to_cpu(id->word120);
+	id->word121        = __le16_to_cpu(id->word121);
+	id->word122        = __le16_to_cpu(id->word122);
+	id->word123        = __le16_to_cpu(id->word123);
+	id->word124        = __le16_to_cpu(id->word124);
+	id->word125        = __le16_to_cpu(id->word125);
+	id->word126        = __le16_to_cpu(id->word126);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->security       = __le16_to_cpu(id->security);
+	for (i=0; i<127; i++)
+	        id->reserved[i] = __le16_to_cpu(id->reserved[i]);
X }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.2.7/linux/arch/ppc/kernel/signal.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/signal.c	Thu Apr 29 12:39:01 1999
@@ -1,7 +1,7 @@
X /*
X  *  linux/arch/ppc/kernel/signal.c
X  *
- *  $Id: signal.c,v 1.23 1999/03/01 16:51:53 cort Exp $
+ *  $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $
X  *
X  *  PowerPC version 
X  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -218,13 +218,8 @@
X 	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
X 		/* Last stacked signal - restore registers */
X 		sr = (struct sigregs *) sigctx.regs;
-#ifdef __SMP__
-		if ( regs->msr & MSR_FP  )
-			smp_giveup_fpu(current);
-#else	
-		if (last_task_used_math == current)
-			giveup_fpu();
-#endif		
+		if (regs->msr & MSR_FP )
+			giveup_fpu(current);
X 		if (copy_from_user(saved_regs, &sr->gp_regs,
X 				   sizeof(sr->gp_regs)))
X 			goto badframe;
@@ -271,13 +266,8 @@
X 
X 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
X 		goto badframe;
-#ifdef __SMP__
-		if ( regs->msr & MSR_FP  )
-			smp_giveup_fpu(current);
-#else	
-		if (last_task_used_math == current)
-			giveup_fpu();
-#endif		
+		if (regs->msr & MSR_FP)
+			giveup_fpu(current);
X 	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
X 	    || __copy_to_user(&frame->fp_regs, current->tss.fpr,
X 			      ELF_NFPREG * sizeof(double))
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.2.7/linux/arch/ppc/kernel/smp.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/smp.c	Thu Apr 29 12:39:01 1999
@@ -1,10 +1,13 @@
X /*
- * $Id: smp.c,v 1.48 1999/03/16 10:40:32 cort Exp $
+ * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
X  *
X  * Smp support for ppc.
X  *
X  * Written by Cort Dougan (co...@cs.nmt.edu) borrowing a great
X  * deal of code from the sparc and intel versions.
+ *
+ * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
+ * (tr...@microux.com, ho...@drgw.net)
X  */
X 
X #include <linux/kernel.h>
@@ -253,6 +256,7 @@
X 	 * cpu 0, the master -- Cort
X 	 */
X 	cpu_callin_map[0] = 1;
+	cpu_callin_map[1] = 0;
X         smp_store_cpu_info(0);
X         active_kernel_processor = 0;
X 	current->processor = 0;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.2.7/linux/arch/ppc/kernel/syscalls.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/syscalls.c	Sat May  8 11:14:01 1999
@@ -205,12 +205,15 @@
X 
X 	lock_kernel();
X 	if (!(flags & MAP_ANONYMOUS)) {
-		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		file = fget(fd);
+		if (!file)
X 			goto out;
X 	}
X 	
X 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
X 	ret = do_mmap(file, addr, len, prot, flags, offset);
+	if (file)
+		fput(file);
X out:
X 	unlock_kernel();
X 	return ret;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.2.7/linux/arch/ppc/kernel/time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/time.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: time.c,v 1.45 1999/03/03 15:09:59 cort Exp $
+ * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $
X  * Common time routines among all ppc machines.
X  *
X  * Written by Cort Dougan (co...@cs.nmt.edu) to merge
@@ -41,18 +41,14 @@
X #include <asm/processor.h>
X #include <asm/nvram.h>
X #include <asm/cache.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
+/* Fixme - Why is this here? - Corey */
X #ifdef CONFIG_8xx
X #include <asm/8xx_immap.h>
X #endif
+#include <asm/machdep.h>
X 
X #include "time.h"
X 
-/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
-int (*set_rtc_time)(unsigned long);
-
X void smp_local_timer_interrupt(struct pt_regs *);
X 
X /* keep track of when we need to update the rtc */
@@ -116,16 +112,21 @@
X 			 */
X 			if ( xtime.tv_sec > last_rtc_update + 660 )
X 			{
-				if (set_rtc_time(xtime.tv_sec) == 0)
+				if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) {
X 					last_rtc_update = xtime.tv_sec;
-				else
-					last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+				}
+				else {
+					/* do it again in 60 s */
+					last_rtc_update = xtime.tv_sec - 60;
+				}
X 			}
X 		}
X 	}
X #ifdef __SMP__
X 	smp_local_timer_interrupt(regs);
X #endif		
+
+	/* Fixme - make this more generic - Corey */
X #ifdef CONFIG_APUS
X 	{
X 		extern void apus_heartbeat (void);
@@ -135,28 +136,6 @@
X 	hardirq_exit(cpu);
X }
X 
-#ifdef CONFIG_MBX
-/* A place holder for time base interrupts, if they are ever enabled.
-*/
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
-	printk("timebase_interrupt()\n");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-mbx_set_rtc_time(unsigned long time)
-{
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
-	((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
-	return(0);
-}
-#endif /* CONFIG_MBX */
-
X /*
X  * This version of gettimeofday has microsecond resolution.
X  */
@@ -203,199 +182,29 @@
X 
X __initfunc(void time_init(void))
X {
-#ifndef CONFIG_MBX
+        if (ppc_md.time_init != NULL)
+        {
+                ppc_md.time_init();
+        }
+
X 	if ((_get_PVR() >> 16) == 1) {
X 		/* 601 processor: dec counts down by 128 every 128ns */
X 		decrementer_count = DECREMENTER_COUNT_601;
X 		count_period_num = COUNT_PERIOD_NUM_601;
X 		count_period_den = COUNT_PERIOD_DEN_601;
+        } else if (!smp_processor_id()) {
+                ppc_md.calibrate_decr();
X 	}
X 
-	switch (_machine) {
-	case _MACH_Pmac:
-		xtime.tv_sec = pmac_get_rtc_time();
-		if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) )
-			pmac_calibrate_decr();
-		if ( !smp_processor_id() )
-			set_rtc_time = pmac_set_rtc_time;
-		break;
-	case _MACH_chrp:
-		chrp_time_init();
-		xtime.tv_sec = chrp_get_rtc_time();
-		if ((_get_PVR() >> 16) != 1)
-			chrp_calibrate_decr();
-		set_rtc_time = chrp_set_rtc_time;
-		break;
-	case _MACH_prep:
-		xtime.tv_sec = prep_get_rtc_time();
-		prep_calibrate_decr();
-		set_rtc_time = prep_set_rtc_time;
-		break;
-#ifdef CONFIG_APUS		
-	case _MACH_apus:
-	{
-		xtime.tv_sec = apus_get_rtc_time();
-		apus_calibrate_decr();
-		set_rtc_time = apus_set_rtc_time;
- 		break;
-	}
-#endif	
-	}
-	xtime.tv_usec = 0;
-#else /* CONFIG_MBX */
-	mbx_calibrate_decr();
-	set_rtc_time = mbx_set_rtc_time;
-
-	/* First, unlock all of the registers we are going to modify.
-	 * To protect them from corruption during power down, registers
-	 * that are maintained by keep alive power are "locked".  To
-	 * modify these registers we have to write the key value to
-	 * the key location associated with the register.
-	 */
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-
-
-	/* Disable the RTC one second and alarm interrupts.
-	*/
-	((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
-						~(RTCSC_SIE | RTCSC_ALE);
-
-	/* Enabling the decrementer also enables the timebase interrupts
-	 * (or from the other point of view, to get decrementer interrupts
-	 * we have to enable the timebase).  The decrementer interrupt
-	 * is wired into the vector table, nothing to do here for that.
-	 */
-	((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
-				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
-					 (TBSCR_TBF | TBSCR_TBE));
-	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
-
-	/* Get time from the RTC.
-	*/
-	xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc;
-	xtime.tv_usec = 0;
+        xtime.tv_sec = ppc_md.get_rtc_time();
+        xtime.tv_usec = 0;
X 
-#endif /* CONFIG_MBX */
X 	set_dec(decrementer_count);
X 	/* mark the rtc/on-chip timer as in sync
X 	 * so we don't update right away
X 	 */
X 	last_rtc_update = xtime.tv_sec;
X }
-
-#ifndef CONFIG_MBX
-/*
- * Uses the on-board timer to calibrate the on-chip decrementer register
- * for prep systems.  On the pmac the OF tells us what the frequency is
- * but on prep we have to figure it out.
- * -- Cort
- */
-int calibrate_done = 0;
-volatile int *done_ptr = &calibrate_done;
-__initfunc(void prep_calibrate_decr(void))
-{
-	unsigned long flags;
-	unsigned long freq, divisor;
-
-	/* the Powerstack II's have trouble with the timer so
-	 * we use a default value -- Cort
-	 */
-	if ( (_prep_type == _PREP_Motorola) &&
-	     ((inb(0x800) & 0xF0) & 0x40) )
-	{
-		static unsigned long t2 = 0;
-		
-		t2 = 998700000/60;
-		freq = t2 * 60;	/* try to make freq/1e6 an integer */
-		divisor = 60;
-		printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
-		       freq, divisor,t2>>20);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-		return;
-	}
-	if ( _prep_type == _PREP_Radstone )
-	{
-		freq = res->VitalProductData.ProcessorBusHz;
-		divisor = 4;
-		printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-		return;
-	}
-	
-	save_flags(flags);
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-	/* set timer to periodic mode */
-	outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
-	/* set the clock to ~100 Hz */
-	outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
-	outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
-	
-	if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
-	__sti();
-	while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
-        restore_flags(flags);
-	free_irq( 0, NULL);
-}
-
-__initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs))
-{
-	unsigned long freq, divisor;
-	static unsigned long t1 = 0, t2 = 0;
-	
-	if ( !t1 )
-		t1 = get_dec();
-	else if (!t2)
-	{
-		t2 = get_dec();
-		t2 = t1-t2;  /* decr's in 1/HZ */
-		t2 = t2*HZ;  /* # decrs in 1s - thus in Hz */
-		freq = t2 * 60;	/* try to make freq/1e6 an integer */
-		divisor = 60;
-		printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
-		       freq, divisor,t2>>20);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-		*done_ptr = 1;
-	}
-}
-
-#else /* CONFIG_MBX */
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four.  Currently, we only
- * support the MBX, which is system clock divided by sixteen.
- */
-__initfunc(void mbx_calibrate_decr(void))
-{
-	bd_t	*binfo = (bd_t *)res;
-	int freq, fp, divisor;
-
-	if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
-		printk("WARNING: Wrong decrementer source clock.\n");
-
-	/* The manual says the frequency is in Hz, but it is really
-	 * as MHz.  The value 'fp' is the number of decrementer ticks
-	 * per second.
-	 */
-	fp = (binfo->bi_intfreq * 1000000) / 16;
-	freq = fp*60;	/* try to make freq/1e6 an integer */
-        divisor = 60;
-        printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
-        decrementer_count = freq / HZ / divisor;
-        count_period_num = divisor;
-        count_period_den = freq / 1000000;
-}
-#endif /* CONFIG_MBX */
X 
X /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
X  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h
--- v2.2.7/linux/arch/ppc/kernel/time.h	Thu Apr 23 20:21:29 1998
+++ linux/arch/ppc/kernel/time.h	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
X /*
- * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $
+ * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $
X  * Common time prototypes and such for all ppc machines.
X  *
X  * Written by Cort Dougan (co...@cs.nmt.edu) to merge
@@ -9,32 +9,15 @@
X #include <linux/mc146818rtc.h>
X 
X /* time.c */
-void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
-void prep_calibrate_decr(void);
-void pmac_calibrate_decr(void);
-extern void apus_calibrate_decr(void);
X extern unsigned decrementer_count;
X extern unsigned count_period_num;
X extern unsigned count_period_den;
-extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
X 			    unsigned int, unsigned int, unsigned int);
X extern void to_tm(int tim, struct rtc_time * tm);
X extern unsigned long last_rtc_update;
X 
-/* pmac/prep/chrp_time.c */
-unsigned long prep_get_rtc_time(void);
-unsigned long pmac_get_rtc_time(void);
-unsigned long chrp_get_rtc_time(void);
-unsigned long apus_get_rtc_time(void);
-int prep_set_rtc_time(unsigned long nowtime);
-int pmac_set_rtc_time(unsigned long nowtime);
-int chrp_set_rtc_time(unsigned long nowtime);
-int apus_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void chrp_calibrate_decr(void);
-void chrp_time_init(void);
X int via_calibrate_decr(void);
-void mbx_calibrate_decr(void);
X 
X /* Accessor functions for the decrementer register. */
X static __inline__ unsigned int get_dec(void)
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.2.7/linux/arch/ppc/kernel/traps.c	Thu Jan  7 15:11:36 1999
+++ linux/arch/ppc/kernel/traps.c	Thu Apr 29 12:39:01 1999
@@ -191,13 +191,8 @@
X {
X 	int fixed;
X 
-#ifdef __SMP__
-	if (regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else	
-	if (last_task_used_math == current)
-		giveup_fpu();
-#endif	
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
X 	fixed = fix_alignment(regs);
X 	if (fixed == 1) {
X 		regs->nip += 4;	/* skip over emulated instruction */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/lib/strcase.c linux/arch/ppc/lib/strcase.c
--- v2.2.7/linux/arch/ppc/lib/strcase.c	Sat Aug 16 09:51:08 1997
+++ linux/arch/ppc/lib/strcase.c	Thu Apr 29 12:39:01 1999
@@ -10,3 +10,14 @@
X 	} while (c1 == c2 && c1 != 0);
X 	return c1 - c2;
X }
+
+int strncasecmp(const char *s1, const char *s2, int n)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while ((--n > 0) && c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/mbxboot/head.S linux/arch/ppc/mbxboot/head.S
--- v2.2.7/linux/arch/ppc/mbxboot/head.S	Fri Apr 16 14:47:30 1999
+++ linux/arch/ppc/mbxboot/head.S	Thu Apr 29 12:39:01 1999
@@ -6,7 +6,7 @@
X 	.text
X 
X /*
- * $Id: head.S,v 1.2 1999/02/17 06:29:41 cort Exp $
+ * $Id: head.S,v 1.4 1999/04/22 06:32:09 davem Exp $
X  *	
X  * This code is loaded by the ROM loader at some arbitrary location.
X  * Move it to high memory so that it can load the kernel at 0x0000.
@@ -67,7 +67,7 @@
X 	mr      r11, r21
X 	lis	r8,start@h
X 	ori	r8,r8,start@l
-	li	r9,end@h
+	lis	r9,end@h
X 	ori	r9,r9,end@l
X 	sub	r7,r8,r9
X 	srwi	r7,r7,2
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.2.7/linux/arch/ppc/mm/fault.c	Thu Jan  7 15:11:36 1999
+++ linux/arch/ppc/mm/fault.c	Tue May 11 08:24:32 1999
@@ -140,7 +140,8 @@
X 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
X 			goto bad_area;
X 	}
-	handle_mm_fault(current, vma, address, error_code & 0x02000000);
+	if (!handle_mm_fault(current, vma, address, error_code & 0x02000000))
+		goto bad_area;
X 	up(&mm->mmap_sem);
X 	/*
X 	 * keep track of tlb+htab misses that are good addrs but
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.2.7/linux/arch/ppc/mm/init.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/mm/init.c	Tue May 11 08:24:32 1999
@@ -1,5 +1,5 @@
- /*
- *  $Id: init.c,v 1.150 1999/03/10 08:16:33 cort Exp $
+/*
+ *  $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $
X  *
X  *  PowerPC version 
X  *    Copyright (C) 1995-1996 Gary Thomas (g...@linuxppc.org)
@@ -119,12 +119,19 @@
X PTE *Hash, *Hash_end;
X unsigned long Hash_size, Hash_mask;
X #ifndef CONFIG_8xx
+#ifdef CONFIG_PPC64
+unsigned long long _SDR1;
+#else
X unsigned long _SDR1;
+#endif
X static void hash_init(void);
X union ubat {			/* BAT register values to be loaded */
X 	BAT	bat;
-	P601_BAT bat_601;
+#ifdef CONFIG_PPC64
+	u64	word[2];
+#else
X 	u32	word[2];
+#endif	
X } BATS[4][2];			/* 4 pairs of IBAT, DBAT */
X 
X struct batrange {		/* stores address ranges mapped by BATs */
@@ -132,6 +139,8 @@
X 	unsigned long limit;
X 	unsigned long phys;
X } bat_addrs[4];
+unsigned long inline v_mapped_by_bats(unsigned long);
+unsigned long inline p_mapped_by_bats(unsigned long);
X #endif /* CONFIG_8xx */
X 
X /*
@@ -332,15 +341,40 @@
X 	 * virt == phys; for addresses below this we use
X 	 * space going down from ioremap_base (ioremap_bot
X 	 * records where we're up to).
-	 *
-	 * We should also look out for a frame buffer and
-	 * map it with a free BAT register, if there is one.
X 	 */
X 	p = addr & PAGE_MASK;
X 	size = PAGE_ALIGN(addr + size) - p;
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using.
+	 * mem_init() sets high_memory so only do the check after that.
+	 */
+	if ( mem_init_done && (p < virt_to_phys(high_memory)) )
+	{
+		printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,
+		       __builtin_return_address(0));
+		return NULL;
+	}
+
X 	if (size == 0)
X 		return NULL;
X 
+#ifndef CONFIG_8xx
+	/*
+	 * Is it already mapped?  Perhaps overlapped by a previous
+	 * BAT mapping.  If the whole area is mapped then we're done,
+	 * otherwise remap it since we want to keep the virt addrs for
+	 * each request contiguous.
+	 *
+	 * We make the assumption here that if the bottom and top
+	 * of the range we want are mapped then it's mapped to the
+	 * same virt address (and this is contiguous).
+	 *  -- Cort
+	 */
+	if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
+		goto out;
+#endif /* CONFIG_8xx */
+	
X 	if (mem_init_done) {
X 		struct vm_struct *area;
X 		area = get_vm_area(size);
@@ -358,10 +392,17 @@
X 		flags |= pgprot_val(PAGE_KERNEL);
X 	if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
X 		flags |= _PAGE_GUARDED;
+
+#ifndef CONFIG_8xx	
+	/*
+	 * Is it a candidate for a BAT mapping?
+	 */
+#endif /* CONFIG_8xx */
+	
X 	for (i = 0; i < size; i += PAGE_SIZE)
X 		map_page(&init_task, v+i, p+i, flags);
-
-	return (void *) (v + (addr & ~PAGE_MASK));
+out:	
+	return (void *) (v + (p & ~PAGE_MASK));
X }
X 
X void iounmap(void *addr)
@@ -412,9 +453,7 @@
X {
X 	pmd_t *pd;
X 	pte_t *pg;
-#ifndef CONFIG_8xx
-	int b;
-#endif
+	
X 	if (tsk->mm->pgd == NULL) {
X 		/* Allocate upper level page map */
X 		tsk->mm->pgd = (pgd_t *) MMU_get_page();
@@ -422,20 +461,8 @@
X 	/* Use upper 10 bits of VA to index the first level map */
X 	pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
X 	if (pmd_none(*pd)) {
-#ifndef CONFIG_8xx
-		/*
-		 * Need to allocate second-level table, but first
-		 * check whether this address is already mapped by
-		 * the BATs; if so, don't bother allocating the page.
-		 */
-		for (b = 0; b < 4; ++b) {
-			if (va >= bat_addrs[b].start
-			    && va <= bat_addrs[b].limit) {
-				/* XXX should check the phys address matches */
-				return;
-			}
-		}
-#endif /* CONFIG_8xx */
+		if ( v_mapped_by_bats(va) )
+			return;
X 		pg = (pte_t *) MMU_get_page();
X 		pmd_val(*pd) = (unsigned long) pg;
X 	}
@@ -680,6 +707,33 @@
X static void sort_mem_pieces(struct mem_pieces *);
X static void coalesce_mem_pieces(struct mem_pieces *);
X 
+/*
+ * Return 1 if this VA is mapped by BATs
+ */
+unsigned long inline v_mapped_by_bats(unsigned long va)
+{
+	int b;
+	for (b = 0; b < 4; ++b)
+		if (va >= bat_addrs[b].start
+	    	    && va < bat_addrs[b].limit)
+			return 1;
+	return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long inline p_mapped_by_bats(unsigned long pa)
+{
+	int b;
+	for (b = 0; b < 4; ++b)
+		if (pa >= bat_addrs[b].phys
+	    	    && pa < (bat_addrs[b].limit-bat_addrs[b].start)
+		              +bat_addrs[b].phys)
+			return bat_addrs[b].start+(pa-bat_addrs[b].phys);
+	return 0;
+}
+
X __initfunc(static void sort_mem_pieces(struct mem_pieces *mp))
X {
X 	unsigned long a, s;
@@ -836,7 +890,7 @@
X 
X 		setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
X 		done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
-		if (done < tot) {
+		if ((done < tot) && !bat_addrs[3].limit) {
X 			/* use BAT3 to cover a bit more */
X 			tot -= done;
X 			for (bl = 128<<10; bl < max_size; bl <<= 1)
@@ -990,11 +1044,13 @@
X 	switch (_machine) {
X 	case _MACH_prep:
X 		setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
-		setbat(1, 0xd0000000, 0xc0000000, 0x10000000, IO_PAGE);
+		setbat(1, 0xf0000000, 0xc0000000, 0x08000000, IO_PAGE);
+		ioremap_base = 0xf0000000;
X 		break;
X 	case _MACH_chrp:
X 		setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE);
X 		setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+		setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
X 		break;
X 	case _MACH_Pmac:
X 		{
@@ -1245,7 +1301,7 @@
X 	int i;
X 	
X 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (768<<20)	
+#define RAM_LIMIT (768<<20)
X 
X 	memory_node = find_devices("memory");
X 	if (memory_node == NULL) {
@@ -1449,10 +1505,18 @@
X 	 * up to a maximum of 2MB.
X 	 */
X 	ramsize = (ulong)end_of_DRAM - KERNELBASE;
+#ifdef CONFIG_PPC64	
+	Hash_mask = 0;
+	for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
+		;
+	Hash_size = h;
+	Hash_mask << 10;  /* so setting _SDR1 works the same -- Cort */
+#else
X 	for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
X 		;
X 	Hash_size = h;
X 	Hash_mask = (h >> 6) - 1;
+#endif	
X 	
X #ifdef NO_RELOAD_HTAB
X 	/* shrink the htab since we don't use it on 603's -- Cort */
@@ -1530,4 +1594,3 @@
X 	}
X }
X #endif /* ndef CONFIG_8xx */
-
diff -u --recursive --new-file v2.2.7/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.2.7/linux/arch/sparc/kernel/entry.S	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc/kernel/entry.S	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.158 1999/04/27 14:35:07 davem Exp $
+/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $
X  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
X  *
X  * Copyright (C) 1995 David S. Miller (da...@caip.rutgers.edu)
@@ -1476,7 +1476,7 @@
X 	wr	%l0, PSR_ET, %psr
X 	WRITE_PAUSE
X 	call	schedule_tail
-	 nop
+	 mov	%g3, %o0
X 	b	C_LABEL(ret_sys_call)
X 	 ld	[%sp + REGWIN_SZ + PT_I0], %o0
X #endif
diff -u --recursive --new-file v2.2.7/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.2.7/linux/arch/sparc/kernel/process.c	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc/kernel/process.c	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.136 1999/04/16 01:20:33 anton Exp $
+/*  $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $
X  *  linux/arch/sparc/kernel/process.c
X  *
X  *  Copyright (C) 1995 David S. Miller (da...@caip.rutgers.edu)
@@ -63,6 +63,8 @@
X 	/* endless idle loop with no priority at all */
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();
+
X 	for (;;) {
X 		if (ARCH_SUN4C_SUN4) {
X 			static int count = HZ;
@@ -111,6 +113,8 @@
X 	/* endless idle loop with no priority at all */
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();
+
X 	while(1) {
X 		if(current->need_resched) {
X 			schedule();
diff -u --recursive --new-file v2.2.7/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.2.7/linux/arch/sparc/kernel/sun4d_smp.c	Thu Nov 19 09:56:27 1998
+++ linux/arch/sparc/kernel/sun4d_smp.c	Tue May 11 08:24:31 1999
@@ -190,6 +190,7 @@
X 	current->processor = boot_cpu_id;
X 	smp_store_cpu_info(boot_cpu_id);
X 	smp_setup_percpu_timer();
+	init_idle();
X 	local_flush_cache_all();
X 	if(linux_num_cpus == 1)
X 		return;  /* Not an MP box. */
@@ -211,6 +212,7 @@
X 			p = task[++cpucount];
X 
X 			p->processor = i;
+			p->has_cpu = 1; /* we schedule the first task manually */
X 			current_set[i] = p;
X 			
X 			for (no = 0; no < linux_num_cpus; no++)
diff -u --recursive --new-file v2.2.7/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.2.7/linux/arch/sparc/kernel/sun4m_smp.c	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc/kernel/sun4m_smp.c	Tue May 11 08:24:31 1999
@@ -161,6 +161,7 @@
X 	smp_store_cpu_info(boot_cpu_id);
X 	set_irq_udt(mid_xlate[boot_cpu_id]);
X 	smp_setup_percpu_timer();
+	init_idle();
X 	local_flush_cache_all();
X 	if(linux_num_cpus == 1)
X 		return;  /* Not an MP box. */
@@ -180,6 +181,7 @@
X 			p = task[++cpucount];
X 
X 			p->processor = i;
+			p->has_cpu = 1; /* we schedule the first task manually */
X 			current_set[i] = p;
X 
X 			/* See trampoline.S for details... */
diff -u --recursive --new-file v2.2.7/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.2.7/linux/arch/sparc/kernel/sys_sparc.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc/kernel/sys_sparc.c	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.51 1999/03/20 22:02:00 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
X  * linux/arch/sparc/kernel/sys_sparc.c
X  *
X  * This file contains various random system calls that
@@ -231,7 +231,7 @@
X 	
X 	if (count++ > 5) return -ENOSYS;
X 	lock_kernel();
-	printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]);
+	printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]);
X #ifdef DEBUG_UNIMP_SYSCALL	
X 	show_regs (regs);
X #endif
diff -u --recursive --new-file v2.2.7/linux/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c
--- v2.2.7/linux/arch/sparc/mm/iommu.c	Fri May  8 23:14:46 1998
+++ linux/arch/sparc/mm/iommu.c	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.9 1998/04/15 14:58:37 jj Exp $
+/* $Id: iommu.c,v 1.10 1999/05/07 17:03:34 jj Exp $
X  * iommu.c:  IOMMU specific routines for memory management.
X  *
X  * Copyright (C) 1995 David S. Miller  (da...@caip.rutgers.edu)
@@ -51,8 +51,7 @@
X 	unsigned long tmp;
X 	struct iommu_struct *iommu;
X 	struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-	int i, j, k, l, m;
-	struct iommu_alloc { unsigned long addr; int next; } *ia;
+	int i;
X 
X 	iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
X 	prom_getproperty(iommund, "reg", (void *) iommu_promregs,
@@ -97,62 +96,18 @@
X 	ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
X 
X 	/* Stupid alignment constraints give me a headache. 
-	   We want to get very large aligned memory area, larger than
-	   maximum what get_free_pages gives us (128K): we need
-	   256K or 512K or 1M or 2M aligned to its size. */
-	ia = (struct iommu_alloc *) kmalloc (sizeof(struct iommu_alloc) * 128, GFP_ATOMIC);
-	for (i = 0; i < 128; i++) {
-		ia[i].addr = 0;
-		ia[i].next = -1;
-	}
-	k = 0;
-	for (i = 0; i < 128; i++) {
-		ia[i].addr = __get_free_pages(GFP_DMA, 5);
-		if (ia[i].addr <= ia[k].addr) {
-			if (i) {
-				ia[i].next = k;
-				k = i;
-			}			
-		} else {
-			for (m = k, l = ia[k].next; l != -1; m = l, l = ia[l].next)
-				if (ia[i].addr <= ia[l].addr) {
-					ia[i].next = l;
-					ia[m].next = i;
-				}
-			if (l == -1)
-				ia[m].next = i;
-		}
-		for (m = -1, j = 0, l = k; l != -1; l = ia[l].next) {
-			if (!(ia[l].addr & (ptsize - 1))) {
-				tmp = ia[l].addr;
-				m = l;
-				j = 128 * 1024;
-			} else if (m != -1) {
-				if (ia[l].addr != tmp + j)
-					m = -1;
-				else {
-					j += 128 * 1024;
-					if (j == ptsize) {
-						break;
-					}
-				}
-			}
-		}
-		if (l != -1)
+	   We need 256K or 512K or 1M or 2M area aligned to
+           its size and current gfp will fortunately give
+           it to us. */
+	for (i = 6; i < 9; i++)
+		if ((1 << (i + PAGE_SHIFT)) == ptsize)
X 			break;
-	}
-	if (i == 128) {
+        tmp = __get_free_pages(GFP_DMA, i);
+	if (!tmp) {
X 		prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize);
X 		prom_halt();
X 	}
-	for (l = m, j = 0; j < ptsize; j += 128 * 1024, l = ia[l].next)
-		ia[l].addr = 0;
-	for (l = k; l != -1; l = ia[l].next)
-		if (ia[l].addr)
-			free_pages(ia[l].addr, 5);
-	kfree (ia);
X 	iommu->lowest = iommu->page_table = (iopte_t *)tmp;
-	
X 
X 	/* Initialize new table. */
X 	flush_cache_all();
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.2.7/linux/arch/sparc64/kernel/cpu.c	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc64/kernel/cpu.c	Tue May 11 08:24:31 1999
@@ -65,7 +65,7 @@
X 	long ver, fpu_vers;
X 	long fprs;
X 	
-	cpuid = smp_processor_id();
+	cpuid = hard_smp_processor_id();
X 
X 	fprs = fprs_read ();
X 	fprs_write (FPRS_FEF);
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.2.7/linux/arch/sparc64/kernel/devices.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc64/kernel/devices.c	Tue May 11 08:24:31 1999
@@ -73,6 +73,9 @@
X 	
X 	prom_cpu_nodes[0] = prom_node_cpu;
X 
+	mem_start = central_probe(mem_start);
+
X 	cpu_probe();
-	return central_probe(mem_start);
+
+	return mem_start;
X }
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.2.7/linux/arch/sparc64/kernel/ebus.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc64/kernel/ebus.c	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.35 1999/01/26 14:34:11 jj Exp $
+/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $
X  * ebus.c: PCI to EBus bridge device.
X  *
X  * Copyright (C) 1997  Eddie C. Dost  (e...@skynet.be)
@@ -35,9 +35,6 @@
X #ifdef CONFIG_SUN_OPENPROMIO
X extern int openprom_init(void);
X #endif
-#ifdef CONFIG_SPARCAUDIO
-extern int sparcaudio_init(void);
-#endif
X #ifdef CONFIG_SUN_AUXIO
X extern void auxio_probe(void);
X #endif
@@ -398,9 +395,6 @@
X 
X #ifdef CONFIG_SUN_OPENPROMIO
X 	openprom_init();
-#endif
-#ifdef CONFIG_SPARCAUDIO
-	sparcaudio_init();
X #endif
X #ifdef CONFIG_SUN_BPP
X 	bpp_init();
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.2.7/linux/arch/sparc64/kernel/entry.S	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc64/kernel/entry.S	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.102 1999/03/29 12:38:09 jj Exp $
+/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $
X  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
X  *
X  * Copyright (C) 1995,1997 David S. Miller (da...@caip.rutgers.edu)
@@ -766,6 +766,7 @@
X 		 */
X #ifdef __SMP__
X 		andn		%o7, 0x100, %l0
+		mov		%g5, %o0	/* 'prev' */
X 		call		schedule_tail
X 		 sth		%l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
X #else
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.2.7/linux/arch/sparc64/kernel/ioctl32.c	Mon Mar 29 11:09:11 1999
+++ linux/arch/sparc64/kernel/ioctl32.c	Tue May 11 08:24:31 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.60 1999/03/22 10:40:54 jj Exp $
+/* $Id: ioctl32.c,v 1.62 1999/05/01 09:17:44 davem Exp $
X  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
X  *
X  * Copyright (C) 1997  Jakub Jelinek  (j...@sunsite.mff.cuni.cz)
@@ -26,6 +26,7 @@
X #include <linux/fs.h>
X #include <linux/file.h>
X #include <linux/fd.h>
+#include <linux/ppp_defs.h>
X #include <linux/if_ppp.h>
X #include <linux/mtio.h>
X #include <linux/cdrom.h>
@@ -35,6 +36,7 @@
X #include <linux/vt_kern.h>
X #include <linux/fb.h>
X #include <linux/ext2_fs.h>
+#include <linux/videodev.h>
X 
X #include <scsi/scsi.h>
X /* Ugly hack. */
@@ -117,6 +119,247 @@
X 	return sys_ioctl(fd, cmd, arg);
X }
X  
+struct video_tuner32 {
+	s32 tuner;
+	u8 name[32];
+	u32 rangelow, rangehigh;
+	u32 flags;
+	u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if(get_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__get_user(kp->name[i], &up->name[i]);
+	__get_user(kp->rangelow, &up->rangelow);
+	__get_user(kp->rangehigh, &up->rangehigh);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->mode, &up->mode);
+	__get_user(kp->signal, &up->signal);
+	return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+	int i;
+
+	if(put_user(kp->tuner, &up->tuner))
+		return -EFAULT;
+	for(i = 0; i < 32; i++)
+		__put_user(kp->name[i], &up->name[i]);
+	__put_user(kp->rangelow, &up->rangelow);
+	__put_user(kp->rangehigh, &up->rangehigh);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->mode, &up->mode);
+	__put_user(kp->signal, &up->signal);
+	return 0;
+}
+
+struct video_buffer32 {
+	/* void * */ u32 base;
+	s32 height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp;
+
+	if(get_user(tmp, &up->base))
+		return -EFAULT;
+	kp->base = (void *) ((unsigned long)tmp);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->depth, &up->depth);
+	__get_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+	u32 tmp = (u32)((unsigned long)kp->base);
+
+	if(put_user(tmp, &up->base))
+		return -EFAULT;
+	__put_user(kp->height, &up->height);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->depth, &up->depth);
+	__put_user(kp->bytesperline, &up->bytesperline);
+	return 0;
+}
+
+struct video_clip32 {
+	s32 x, y, width, height;
+	/* struct video_clip32 * */ u32 next;
+};
+
+struct video_window32 {
+	u32 x, y, width, height, chromakey, flags;
+	/* struct video_clip32 * */ u32 clips;
+	s32 clipcount;
+};
+
+static void free_kvideo_clips(struct video_window *kp)
+{
+	struct video_clip *cp;
+
+	cp = kp->clips;
+	if(cp != NULL)
+		kfree(cp);
+}
+
+static int get_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	struct video_clip32 *ucp;
+	struct video_clip *kcp;
+	int nclips, err, i;
+	u32 tmp;
+
+	if(get_user(kp->x, &up->x))
+		return -EFAULT;
+	__get_user(kp->y, &up->y);
+	__get_user(kp->width, &up->width);
+	__get_user(kp->height, &up->height);
+	__get_user(kp->chromakey, &up->chromakey);
+	__get_user(kp->flags, &up->flags);
+	__get_user(kp->clipcount, &up->clipcount);
+	__get_user(tmp, &up->clips);
+	ucp = (struct video_clip32 *)A(tmp);
+	kp->clips = NULL;
+
+	nclips = kp->clipcount;
+	if(nclips == 0)
+		return 0;
+
+	if(ucp == 0)
+		return -EINVAL;
+
+	/* Peculiar interface... */
+	if(nclips < 0)
+		nclips = VIDEO_CLIPMAP_SIZE;
+
+	kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
+	err = -ENOMEM;
+	if(kcp == NULL)
+		goto cleanup_and_err;
+
+	kp->clips = kcp;
+	for(i = 0; i < nclips; i++) {
+		__get_user(kcp[i].x, &ucp[i].x);
+		__get_user(kcp[i].y, &ucp[i].y);
+		__get_user(kcp[i].width, &ucp[i].width);
+		__get_user(kcp[i].height, &ucp[i].height);
+		kcp[nclips].next = NULL;
+	}
+
+	return 0;
+
+cleanup_and_err:
+	free_kvideo_clips(kp);
+	return err;
+}
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+	if(put_user(kp->x, &up->x))
+		return -EFAULT;
+	__put_user(kp->y, &up->y);
+	__put_user(kp->width, &up->width);
+	__put_user(kp->height, &up->height);
+	__put_user(kp->chromakey, &up->chromakey);
+	__put_user(kp->flags, &up->flags);
+	__put_user(kp->clipcount, &up->clipcount);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 12'
echo 'File patch-2.2.8 is continued in part 13'
echo 13 > _shar_seq_.tmp
#!/bin/sh
# this is part 13 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 13; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+	return 0;
+}
+
+#define VIDIOCGTUNER32		_IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32		_IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32		_IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32		_IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32		_IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32		_IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32		_IOR('v',14, u32)
+#define VIDIOCSFREQ32		_IOW('v',15, u32)
+
+static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	union {
+		struct video_tuner vt;
+		struct video_buffer vb;
+		struct video_window vw;
+		unsigned long vx;
+	} karg;
+	mm_segment_t old_fs = get_fs();
+	void *up = (void *)arg;
+	int err = 0;
+
+	/* First, convert the command. */
+	switch(cmd) {
+	case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+	case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+	case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+	case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+	case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+	case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+	case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+	case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+	};
+
+	switch(cmd) {
+	case VIDIOCSTUNER:
+	case VIDIOCGTUNER:
+		err = get_video_tuner32(&karg.vt, up);
+		break;
+
+	case VIDIOCSWIN:
+		err = get_video_window32(&karg.vw, up);
+		break;
+
+	case VIDIOCSFBUF:
+		err = get_video_buffer32(&karg.vb, up);
+		break;
+
+	case VIDIOCSFREQ:
+		err = get_user(karg.vx, (u32 *)up);
+		break;
+	};
+	if(err)
+		goto out;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&karg);
+	set_fs(old_fs);
+
+	if(cmd == VIDIOCSWIN)
+		free_kvideo_clips(&karg.vw);
+
+	if(err == 0) {
+		switch(cmd) {
+		case VIDIOCGTUNER:
+			err = put_video_tuner32(&karg.vt, up);
+			break;
+
+		case VIDIOCGWIN:
+			err = put_video_window32(&karg.vw, up);
+			break;
+
+		case VIDIOCGFBUF:
+			err = put_video_buffer32(&karg.vb, up);
+			break;
+
+		case VIDIOCGFREQ:
+			err = put_user(((u32)karg.vx), (u32 *)up);
+			break;
+		};
+	}
+out:
+	return err;
+}
+
X struct timeval32 {
X 	int tv_sec;
X 	int tv_usec;
@@ -1600,6 +1843,17 @@
X 		error = do_ext2_ioctl(fd, cmd, arg);
X 		goto out;
X 		
+	case VIDIOCGTUNER32:
+	case VIDIOCSTUNER32:
+	case VIDIOCGWIN32:
+	case VIDIOCSWIN32:
+	case VIDIOCGFBUF32:
+	case VIDIOCSFBUF32:
+	case VIDIOCGFREQ32:
+	case VIDIOCSFREQ32:
+		error = do_video_ioctl(fd, cmd, arg);
+		goto out;
+
X 	/* List here exlicitly which ioctl's are known to have
X 	 * compatable types passed or none at all...
X 	 */
@@ -1792,6 +2046,33 @@
X 	/* Little v */
X 	case VUIDSFORMAT:
X 	case VUIDGFORMAT:
+
+	/* Little v, the video4linux ioctls */
+	case VIDIOCGCAP:
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
+	case VIDIOCGPICT:
+	case VIDIOCSPICT:
+	case VIDIOCCAPTURE:
+	case VIDIOCKEY:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+	case VIDIOCSYNC:
+	case VIDIOCMCAPTURE:
+	case VIDIOCGMBUF:
+	case VIDIOCGUNIT:
+	case VIDIOCGCAPTURE:
+	case VIDIOCSCAPTURE:
+
+	/* BTTV specific... */
+	case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
+	case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+	case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+	case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+	case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
X 
X 	/* Little p (/dev/rtc, /dev/envctrl, etc.) */
X 	case RTCGET:
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.2.7/linux/arch/sparc64/kernel/process.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc64/kernel/process.c	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.90 1999/03/22 02:12:16 davem Exp $
+/*  $Id: process.c,v 1.92 1999/05/08 23:04:48 davem Exp $
X  *  arch/sparc64/kernel/process.c
X  *
X  *  Copyright (C) 1995, 1996 David S. Miller (da...@caip.rutgers.edu)
@@ -54,6 +54,8 @@
X 	/* endless idle loop with no priority at all */
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();
+
X 	for (;;) {
X 		/* If current->need_resched is zero we should really
X 		 * setup for a system wakup event and execute a shutdown
@@ -79,6 +81,8 @@
X {
X 	current->priority = 0;
X 	current->counter = -100;
+	init_idle();
+
X 	while(1) {
X 		if (current->need_resched != 0) {
X 			unidle_me();
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.2.7/linux/arch/sparc64/kernel/smp.c	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc64/kernel/smp.c	Tue May 11 08:24:32 1999
@@ -97,7 +97,7 @@
X 	cpu_data[id].pte_cache			= NULL;
X 	cpu_data[id].pgdcache_size		= 0;
X 	cpu_data[id].pgd_cache			= NULL;
-	cpu_data[id].idle_volume		= 0;
+	cpu_data[id].idle_volume		= 1;
X 
X 	for(i = 0; i < 16; i++)
X 		cpu_data[id].irq_worklists[i] = 0;
@@ -196,6 +196,7 @@
X 	__sti();
X 	smp_store_cpu_info(boot_cpu_id);
X 	smp_tune_scheduling();
+	init_idle();
X 
X 	if(linux_num_cpus == 1)
X 		return;
@@ -217,6 +218,7 @@
X 			kernel_thread(start_secondary, NULL, CLONE_PID);
X 			p = task[++cpucount];
X 			p->processor = i;
+			p->has_cpu = 1; /* we schedule the first task manually */
X callin_flag = 0;
X 			for (no = 0; no < linux_num_cpus; no++)
X 				if (linux_cpus[no].mid == i)
@@ -460,8 +462,6 @@
X 			mm->cpu_vm_mask = (1UL << smp_processor_id());
X 		goto local_flush_and_out;
X 	} else {
-		spin_lock(&scheduler_lock);
-
X 		/* Try to handle two special cases to avoid cross calls
X 		 * in common scenerios where we are swapping process
X 		 * pages out.
@@ -471,16 +471,12 @@
X 			/* A dead context cannot ever become "alive" until
X 			 * a task switch is done to it.
X 			 */
-			spin_unlock(&scheduler_lock);
X 			return; /* It's dead, nothing to do. */
X 		}
X 		if(mm->cpu_vm_mask == (1UL << smp_processor_id())) {
-			spin_unlock(&scheduler_lock);
X 			__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
X 			return; /* Only local flush is necessary. */
X 		}
-
-		spin_unlock(&scheduler_lock);
X 	}
X 	smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
X 
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.2.7/linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Mar 23 14:35:47 1999
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.57 1999/03/14 20:51:28 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $
X  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
X  *
X  * Copyright (C) 1996 David S. Miller (da...@caip.rutgers.edu)
@@ -90,7 +90,6 @@
X extern void dump_thread(struct pt_regs *, struct user *);
X 
X #ifdef __SMP__
-extern spinlock_t scheduler_lock;
X extern spinlock_t kernel_flag;
X extern int smp_num_cpus;
X #ifdef SPIN_LOCK_DEBUG
@@ -120,7 +119,6 @@
X /* used by various drivers */
X #ifdef __SMP__
X /* Kernel wide locking */
-EXPORT_SYMBOL(scheduler_lock);
X EXPORT_SYMBOL(kernel_flag);
X 
X /* Software-IRQ BH locking */
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.2.7/linux/arch/sparc64/mm/init.c	Wed Apr 28 11:37:30 1999
+++ linux/arch/sparc64/mm/init.c	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.126 1999/04/09 16:16:41 jj Exp $
+/*  $Id: init.c,v 1.127 1999/05/08 03:00:38 davem Exp $
X  *  arch/sparc64/mm/init.c
X  *
X  *  Copyright (C) 1996-1999 David S. Miller (da...@caip.rutgers.edu)
@@ -949,8 +949,7 @@
X #define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
X unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
X 
-/* We are always protected by scheduler_lock under SMP.
- * Caller does TLB context flushing on local CPU if necessary.
+/* Caller does TLB context flushing on local CPU if necessary.
X  *
X  * We must be careful about boundary cases so that we never
X  * let the user have CTX 0 (nucleus) or we ever use a CTX
diff -u --recursive --new-file v2.2.7/linux/drivers/Makefile linux/drivers/Makefile
--- v2.2.7/linux/drivers/Makefile	Wed Apr 28 11:37:30 1999
+++ linux/drivers/Makefile	Mon May 10 10:18:34 1999
@@ -47,7 +47,11 @@
X ifeq ($(CONFIG_USB),y)
X SUB_DIRS += usb
X MOD_SUB_DIRS += usb
-endif
+else
+  ifeq ($(CONFIG_USB),m)
+  MOD_SUB_DIRS += usb
+  endif
+endif 
X 
X # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
X # but some of the low-level things may also be modules.
diff -u --recursive --new-file v2.2.7/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.2.7/linux/drivers/block/Config.in	Thu Dec 31 10:28:59 1998
+++ linux/drivers/block/Config.in	Thu Apr 29 12:53:48 1999
@@ -51,13 +51,15 @@
X           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
X       fi
X     fi
-    if [ "$CONFIG_PMAC" = "y" ]; then
-      define_bool CONFIG_BLK_DEV_IDE_PMAC y
-      bool '   PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
-      if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
-        define_bool CONFIG_BLK_DEV_IDEDMA y
-	bool '     Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
-      fi
+    if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+      bool '   Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
+        if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
+          bool '     PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
+          if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
+            define_bool CONFIG_BLK_DEV_IDEDMA y
+            bool '     Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
+          fi
+       fi
X     fi
X     bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
X     if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
diff -u --recursive --new-file v2.2.7/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.2.7/linux/drivers/block/ide-cd.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/block/ide-cd.h	Tue May 11 10:35:45 1999
@@ -363,7 +363,7 @@
X #endif
X 
X #if defined(__BIG_ENDIAN_BITFIELD)
-	__u8 reserved4           : 4;
+	__u8 reserved4           : 1;
X 	/* Drive can read multisession discs. */
X 	__u8 multisession        : 1;
X 	/* Drive can read mode 2, form 2 data. */
diff -u --recursive --new-file v2.2.7/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.2.7/linux/drivers/block/ide.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/block/ide.c	Mon May  3 09:34:51 1999
@@ -813,7 +813,7 @@
X 		ide_end_drive_cmd(drive, stat, err);
X 		return;
X 	}
-	if (stat & BUSY_STAT) {		/* other bits are useless when BUSY */
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
X 		rq->errors |= ERROR_RESET;
X 	} else {
X 		if (drive->media == ide_disk && (stat & ERR_STAT)) {
diff -u --recursive --new-file v2.2.7/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.2.7/linux/drivers/block/rd.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/block/rd.c	Thu Apr 29 11:53:41 1999
@@ -33,11 +33,13 @@
X  *
X  *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
X  *
-* 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
+ * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
X  *		- Chad Page
X  *
X  * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98
X  *
+ * Make block size and block size shift for RAM disks a global macro
+ * and set blk_size for -ENOSPC,     Werner Fink <wer...@suse.de>, Apr '99
X  */
X 
X #include <linux/config.h>
@@ -47,6 +49,7 @@
X #include <linux/romfs_fs.h>
X #include <linux/fs.h>
X #include <linux/kernel.h>
+#include <linux/hdreg.h>
X #include <linux/string.h>
X #include <linux/mm.h>
X #include <linux/mman.h>
@@ -70,6 +73,15 @@
X #define MAJOR_NR RAMDISK_MAJOR
X #include <linux/blk.h>
X 
+/*
+ * We use a block size of 512 bytes in comparision to BLOCK_SIZE
+ * defined in include/linux/blk.h. This because of the finer
+ * granularity for filling up a RAM disk.
+ */
+#define RDBLK_SIZE_BITS		9
+#define RDBLK_SIZE		(1<<RDBLK_SIZE_BITS)
+
+
X /* The RAM disk size is now a parameter */
X #define NUM_RAMDISKS 16		/* This cannot be overridden (yet) */ 
X 
@@ -89,8 +101,10 @@
X /* Various static variables go here.  Most are used only in the RAM disk code.
X  */
X 
-static int rd_length[NUM_RAMDISKS];
-static int rd_blocksizes[NUM_RAMDISKS];
+static unsigned long rd_length[NUM_RAMDISKS];	/* Size of RAM disks in bytes   */
+static int rd_hardsec[NUM_RAMDISKS];		/* Size of real blocks in bytes */
+static int rd_blocksizes[NUM_RAMDISKS];		/* Size of 1024 byte blocks :)  */
+static int rd_kbsize[NUM_RAMDISKS];		/* Size in blocks of 1024 bytes */
X 
X /*
X  * Parameters for the boot-loading of the RAM disk.  These are set by
@@ -120,9 +134,12 @@
X static void rd_request(void)
X {
X 	unsigned int minor;
-	int offset, len;
+	unsigned long offset, len;
X 
X repeat:
+	if (!CURRENT)
+		return;
+
X 	INIT_REQUEST;
X 	
X 	minor = MINOR(CURRENT->rq_dev);
@@ -132,14 +149,20 @@
X 		goto repeat;
X 	}
X 	
-	offset = CURRENT->sector << 9;
-	len = CURRENT->current_nr_sectors << 9;
+	offset = CURRENT->sector << RDBLK_SIZE_BITS;
+	len = CURRENT->current_nr_sectors << RDBLK_SIZE_BITS;
X 
X 	if ((offset + len) > rd_length[minor]) {
X 		end_request(0);
X 		goto repeat;
X 	}
X 
+	if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
+		printk(KERN_INFO "RAMDISK: bad command: %d\n", CURRENT->cmd);
+		end_request(0);
+		goto repeat;
+	}
+
X 	/*
X 	 * If we're reading, fill the buffer with 0's.  This is okay since
X          * we're using protected buffers which should never get freed...
@@ -158,24 +181,31 @@
X 
X static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
X {
+	unsigned int minor;
+
X 	if (!inode || !inode->i_rdev) 	
X 		return -EINVAL;
X 
+	minor = MINOR(inode->i_rdev);
+
X 	switch (cmd) {
X 		case BLKFLSBUF:
X 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
X 			invalidate_buffers(inode->i_rdev);
X 			break;
+
X          	case BLKGETSIZE:   /* Return device size */
X 			if (!arg)  return -EINVAL;
-			return put_user(rd_length[MINOR(inode->i_rdev)] / 512, 
-				 (long *) arg);
-		case BLKSSZGET:
-			/* Block size of media */
-			return put_user(rd_blocksizes[MINOR(inode->i_rdev)],
-						    (int *)arg);
+			return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg);
+
+		case BLKSSZGET:	   /* Block size of media */
+			if (!arg)  return -EINVAL;
+			return put_user(rd_blocksizes[minor], (int *)arg);
+
+		RO_IOCTLS(inode->i_rdev, arg);
+
X 		default:
-			break;
+			return -EINVAL;
X 	};
X 
X 	return 0;
@@ -263,7 +293,7 @@
X 	rd_open,	/* open */
X 	NULL,		/* flush */
X 	rd_release,	/* module needs to decrement use count */
-	block_fsync		/* fsync */ 
+	block_fsync	/* fsync */ 
X };
X 
X /* This is the registration and initialization section of the RAM disk driver */
@@ -279,11 +309,16 @@
X 	blk_dev[MAJOR_NR].request_fn = &rd_request;
X 
X 	for (i = 0; i < NUM_RAMDISKS; i++) {
-		rd_length[i] = (rd_size * 1024);
-		rd_blocksizes[i] = 1024;
+		/* rd_size is given in kB */
+		rd_length[i] = (rd_size << BLOCK_SIZE_BITS);
+		rd_hardsec[i] = RDBLK_SIZE;
+		rd_blocksizes[i] = BLOCK_SIZE;
+		rd_kbsize[i] = (rd_length[i] >> BLOCK_SIZE_BITS);
X 	}
X 
-	blksize_size[MAJOR_NR] = rd_blocksizes;
+	hardsect_size[MAJOR_NR] = rd_hardsec;		/* Size of the RAM disk blocks */
+	blksize_size[MAJOR_NR] = rd_blocksizes;		/* Avoid set_blocksize() check */
+	blk_size[MAJOR_NR] = rd_kbsize;			/* Size of the RAM disk in kB  */
X 
X 	printk("RAM disk driver initialized:  %d RAM disks of %dK size\n",
X 							NUM_RAMDISKS, rd_size);
@@ -295,7 +330,8 @@
X 
X #ifdef MODULE
X 
-MODULE_PARM (rd_size, "1i");
+MODULE_PARM     (rd_size, "1i");
+MODULE_PARM_DESC(rd_size, "Size of each RAM disk.");
X 
X int init_module(void)
X {
@@ -427,7 +463,7 @@
X /*
X  * This routine loads in the RAM disk image.
X  */
-__initfunc(static void rd_load_image(kdev_t device,int offset))
+__initfunc(static void rd_load_image(kdev_t device, int offset, int unit))
X {
X  	struct inode inode, out_inode;
X 	struct file infile, outfile;
@@ -440,7 +476,7 @@
X 	unsigned short devblocks = 0;
X 	char rotator[4] = { '|' , '/' , '-' , '\\' };
X 
-	ram_device = MKDEV(MAJOR_NR, 0);
+	ram_device = MKDEV(MAJOR_NR, unit);
X 
X 	memset(&infile, 0, sizeof(infile));
X 	memset(&inode, 0, sizeof(inode));
@@ -480,9 +516,9 @@
X 		goto done;
X 	}
X 
-	if (nblocks > (rd_length[0] >> BLOCK_SIZE_BITS)) {
+	if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) {
X 		printk("RAMDISK: image too big! (%d/%d blocks)\n",
-		       nblocks, rd_length[0] >> BLOCK_SIZE_BITS);
+		       nblocks, rd_length[unit] >> RDBLK_SIZE_BITS);
X 		goto done;
X 	}
X 		
@@ -538,7 +574,7 @@
X 
X successful_load:
X 	invalidate_buffers(device);
-	ROOT_DEV = MKDEV(MAJOR_NR,0);
+	ROOT_DEV = MKDEV(MAJOR_NR, unit);
X 
X done:
X 	if (infile.f_op->release)
@@ -547,12 +583,21 @@
X }
X 
X 
-__initfunc(void rd_load(void))
+__initfunc(static void rd_load_disk(int n))
X {
+#ifdef CONFIG_BLK_DEV_INITRD
+	extern kdev_t real_root_dev;
+#endif
+
X 	if (rd_doload == 0)
X 		return;
-	
-	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
+
+	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR
+#ifdef CONFIG_BLK_DEV_INITRD
+		&& MAJOR(real_root_dev) != FLOPPY_MAJOR
+#endif
+	)
+		return;
X 
X 	if (rd_prompt) {
X #ifdef CONFIG_BLK_DEV_FD
@@ -563,15 +608,24 @@
X 		wait_for_keypress();
X 	}
X 
-	rd_load_image(ROOT_DEV,rd_image_start);
+	rd_load_image(ROOT_DEV,rd_image_start, n);
X 
X }
X 
+__initfunc(void rd_load(void))
+{
+	rd_load_disk(0);
+}
+
+__initfunc(void rd_load_secondary(void))
+{
+	rd_load_disk(1);
+}
X 
X #ifdef CONFIG_BLK_DEV_INITRD
X __initfunc(void initrd_load(void))
X {
-	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
+	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0);
X }
X #endif
X 
@@ -695,7 +749,14 @@
X crd_load(struct file * fp, struct file *outfp))
X {
X 	int result;
-	
+
+	insize = 0;		/* valid bytes in inbuf */
+	inptr = 0;		/* index of next byte to be processed in inbuf */
+	outcnt = 0;		/* bytes in output buffer */
+	exit_code = 0;
+	bytes_out = 0;
+	crc = (ulg)0xffffffffL; /* shift register contents */
+
X 	crd_infp = fp;
X 	crd_outfp = outfp;
X 	inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
diff -u --recursive --new-file v2.2.7/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.2.7/linux/drivers/cdrom/cdrom.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/cdrom/cdrom.c	Thu Apr 29 11:53:41 1999
@@ -120,11 +120,16 @@
X   2.54 Mar 15, 1999 - Jens Axboe <ax...@image.dk>
X   -- Check capability mask from low level driver when counting tracks as
X   per suggestion from Corey J. Scotts <cst...@blue.weeg.uiowa.edu>.
+  
+  2.55 Apr 25, 1999 - Jens Axboe <ax...@image.dk>
+  -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of
+  CDC_CLOSE_TRAY.
+  -- proc info didn't mask against capabilities mask.
X 
X -------------------------------------------------------------------------*/
X 
-#define REVISION "Revision: 2.54"
-#define VERSION "Id: cdrom.c 2.54 1999/03/15"
+#define REVISION "Revision: 2.55"
+#define VERSION "Id: cdrom.c 2.55 1999/04/25"
X 
X /* I use an error-log mask to give fine grain control over the type of
X    messages dumped to the system logs.  The available masks include: */
@@ -268,7 +273,7 @@
X 	cdo->n_minors = 0;
X         cdi->options = CDO_USE_FFLAGS;
X 	
-	if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
+	if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
X 		cdi->options |= (int) CDO_AUTO_CLOSE;
X 	if (autoeject==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
X 		cdi->options |= (int) CDO_AUTO_EJECT;
@@ -1097,27 +1102,27 @@
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
X 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_CLOSE_TRAY)!=0));
+		((cdi->ops->capability & ~cdi->mask & CDC_CLOSE_TRAY)!=0));
X 
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
X 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_OPEN_TRAY)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_OPEN_TRAY)!=0));
X 
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
X 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_LOCK)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_LOCK)!=0));
X 
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
X 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_SELECT_SPEED)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_SPEED)!=0));
X 
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
X 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_SELECT_DISC)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_DISC)!=0));
X 
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
@@ -1137,7 +1142,7 @@
X 	pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t");
X 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
X 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_PLAY_AUDIO)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0));
X 
X         strcpy(cdrom_drive_info+pos,"\n\n");
X 	*lenp=pos+3;
diff -u --recursive --new-file v2.2.7/linux/drivers/cdrom/mcdx.h linux/drivers/cdrom/mcdx.h
--- v2.2.7/linux/drivers/cdrom/mcdx.h	Wed Jan 20 23:14:05 1999
+++ linux/drivers/cdrom/mcdx.h	Thu Apr 29 11:53:41 1999
@@ -176,8 +176,10 @@
X #define MCDX_ST_DRV 0x00ff		/* mask to query the drive status */
X 
X #ifndef I_WAS_HERE
+#ifndef MODULE
X #warning You have not edited mcdx.h
X #warning Perhaps irq and i/o settings are wrong.
+#endif
X #endif
X 
X /* ex:set ts=4 sw=4: */
diff -u --recursive --new-file v2.2.7/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.2.7/linux/drivers/char/Config.in	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/Config.in	Fri May  7 11:05:30 1999
@@ -137,6 +137,9 @@
X     dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
X   fi
X   dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+  if [ "$CONFIG_PMAC" = "y" ]; then
+    dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
+  fi
X   dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
X   dep_tristate 'SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
X   if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
diff -u --recursive --new-file v2.2.7/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.2.7/linux/drivers/char/Makefile	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/Makefile	Fri May  7 11:05:30 1999
@@ -283,12 +283,12 @@
X endif
X 
X ifeq ($(CONFIG_NVRAM),y)
-  ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),)
+  ifeq ($(CONFIG_PPC),)
X   L_OBJS += nvram.o
X   endif
X else
X   ifeq ($(CONFIG_NVRAM),m)
-    ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),)
+    ifeq ($(CONFIG_PPC),)
X     M_OBJS += nvram.o
X     endif
X   endif
@@ -351,6 +351,14 @@
X else
X   ifeq ($(CONFIG_VIDEO_PMS),m)
X   M_OBJS += pms.o
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_PLANB),y)
+L_OBJS += planb.o
+else
+  ifeq ($(CONFIG_VIDEO_PLANB),m)
+  M_OBJS += planb.o
X   endif
X endif
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.2.7/linux/drivers/char/adbmouse.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/char/adbmouse.c	Thu Apr 29 12:53:48 1999
@@ -113,7 +113,7 @@
X      *  on a logitech mouseman, the right and mid buttons sometimes behave
X      *  strangely until they both have been pressed after booting. */
X     /* data valid only if extended mouse format ! */
-    if (nb == 4)
+    if (nb >= 4)
X 	buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
X 
X     add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
diff -u --recursive --new-file v2.2.7/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.2.7/linux/drivers/char/isicom.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/isicom.c	Fri May  7 11:05:30 1999
@@ -13,6 +13,23 @@
X  *					(fixed range check bug as a side effect)
X  *					Printk clean up
X  *	9/12/98	al...@redhat.com		Rough port to 2.1.x
+ *
+ *
+ *	***********************************************************
+ *
+ *	To use this driver you also need the support package. You 
+ *	can find this in RPM format on
+ *		ftp://ftp.linux.org.uk/pub/linux/alan
+ * 	
+ *	You can find the original tools for this direct from Multitech
+ *		ftp://ftp.multitech.com/ISI-Cards/
+ *
+ *	Having installed the cards the module options (/etc/conf.modules)
+ *
+ *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
+ *
+ *	Omit those entries for boards you don't have installed.
+ *
X  */
X 
X #include <linux/module.h>
diff -u --recursive --new-file v2.2.7/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.2.7/linux/drivers/char/lp.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/char/lp.c	Mon May 10 10:26:31 1999
@@ -202,9 +202,7 @@
X /* Test if the printer is not acking the strobe */
X #define	LP_NO_ACKING(status)	((status) & LP_PACK)
X /* Test if the printer has error conditions */
-#define LP_NO_ERROR(status)					\
-	 (((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) ==	\
-	 (LP_PSELECD|LP_PERRORP))
+#define LP_NO_ERROR(status)	((status) & LP_PERRORP)
X 
X #undef LP_DEBUG
X #undef LP_READ_DEBUG
@@ -424,7 +422,10 @@
X {
X 	unsigned int last = lp_table[minor].last_error;
X 	unsigned char status = r_str(minor);
-	if ((status & LP_POUTPA)) {
+	if (status & LP_PERRORP)
+		/* No error. */
+		last = 0;
+	else if ((status & LP_POUTPA)) {
X 		if (last != LP_POUTPA) {
X 			last = LP_POUTPA;
X 			printk(KERN_INFO "lp%d out of paper\n", minor);
@@ -434,13 +435,12 @@
X 			last = LP_PSELECD;
X 			printk(KERN_INFO "lp%d off-line\n", minor);
X 		}
-	} else if (!(status & LP_PERRORP)) {
+	} else {
X 		if (last != LP_PERRORP) {
X 			last = LP_PERRORP;
-			printk(KERN_INFO "lp%d on fire!\n", minor);
+			printk(KERN_INFO "lp%d on fire\n", minor);
X 		}
X 	}
-	else last = 0;
X 
X 	lp_table[minor].last_error = last;
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.2.7/linux/drivers/char/mem.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/mem.c	Mon May 10 10:18:34 1999
@@ -57,7 +57,10 @@
X #ifdef CONFIG_USB_OHCI
X int ohci_init(void);
X #endif
-
+#ifdef CONFIG_USB_OHCI_HCD
+int ohci_hcd_init(void);
+#endif
+     
X static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
X 			    const char * buf, size_t count, loff_t *ppos)
X {
@@ -605,11 +608,16 @@
X 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
X 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
X 	rand_initialize();
+#ifdef CONFIG_USB
X #ifdef CONFIG_USB_UHCI
X 	uhci_init();
X #endif
X #ifdef CONFIG_USB_OHCI
X 	ohci_init();
+#endif
+#ifdef CONFIG_USB_OHCI_HCD
+        ohci_hcd_init(); 
+#endif
X #endif
X #if defined (CONFIG_FB)
X 	fbmem_init();
diff -u --recursive --new-file v2.2.7/linux/drivers/char/planb.c linux/drivers/char/planb.c
--- v2.2.7/linux/drivers/char/planb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/planb.c	Mon May 10 10:17:28 1999
@@ -0,0 +1,2389 @@
+/* 
+    planb - PlanB frame grabber driver
+
+    PlanB is used in the 7x00/8x00 series of PowerMacintosh
+    Computers as video input DMA controller.
+
+    Copyright (C) 1998 Michel Lanners (ml...@cpu.lu)
+
+    Based largely on the bttv driver by Ralph Metzler (rj...@thp.uni-koeln.de)
+
+    Additional debugging and coding by Takashi Oe (t...@unlinfo.unl.edu)
+	(Some codes are stolen from proposed v4l2 videodev.c
+		of Bill Dirks <di...@rendition.com>)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wrapper.h>
+#include <linux/tqueue.h>
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/irq.h>
+
+#include "planb.h"
+#include "saa7196.h"
+
+
+/* Would you mind for some ugly debugging? */
+//#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
+#define DEBUG(x...) 		/* Don't debug driver */	
+//#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
+#define IDEBUG(x...) 		/* Don't debug interrupt part */
+
+/* Ever seen a Mac with more than 1 of these? */
+#define PLANB_MAX 1
+
+static int planb_num;
+static struct planb planbs[PLANB_MAX];
+static volatile struct planb_registers *planb_regs;
+
+static int def_norm = PLANB_DEF_NORM;	/* default norm */
+
+MODULE_PARM(def_norm, "i");
+MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
+
+/* ------------------ PlanB Exported Functions ------------------ */
+static long planb_write(struct video_device *, const char *, unsigned long, int);
+static long planb_read(struct video_device *, char *, unsigned long, int);
+static int planb_open(struct video_device *, int);
+static void planb_close(struct video_device *);
+static int planb_ioctl(struct video_device *, unsigned int, void *);
+static int planb_init_done(struct video_device *);
+static int planb_mmap(struct video_device *, const char *, unsigned long);
+static void planb_irq(int, void *, struct pt_regs *);
+static void release_planb(void);
+int init_planbs(struct video_init *);
+
+/* ------------------ PlanB Internal Functions ------------------ */
+static int planb_prepare_open(struct planb *);
+static void planb_prepare_close(struct planb *);
+static void saa_write_reg(unsigned char, unsigned char);
+static unsigned char saa_status(int, struct planb *);
+static void saa_set(unsigned char, unsigned char, struct planb *);
+static void saa_init_regs(struct planb *);
+static void * rvmalloc(unsigned long);
+static void rvfree(void *, unsigned long);
+static unsigned long vmalloc_to_bus(void *);
+static unsigned long vmalloc_to_phys(void *);
+static int fbuffer_alloc(struct planb *);
+static int vgrab(struct planb *, struct video_mmap *);
+static void add_clip(struct planb *, struct video_clip *);
+static void fill_cmd_buff(struct planb *);
+static void cmd_buff(struct planb *);
+static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);
+static void overlay_start(struct planb *);
+static void overlay_stop(struct planb *);
+static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,
+	unsigned int);
+static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
+	unsigned int);
+static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,
+	unsigned short, unsigned int, unsigned int);
+static int init_planb(struct planb *);
+static int find_planb(void);
+static void planb_pre_capture(int, int, struct planb *);
+static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,
+					int, int, int, int, int, struct planb *);
+static inline void planb_dbdma_stop(volatile struct dbdma_regs *);
+static unsigned int saa_geo_setup(int, int, int, int, struct planb *);
+static inline int overlay_is_active(struct planb *);
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+static void * rvmalloc(unsigned long size)
+{
+	void *mem, *memptr;
+	unsigned long page;
+        
+	mem=vmalloc(size);
+	if (mem) 
+	{
+		memset(mem, 0, size); /* Clear the ram out, leave no junk */
+		memptr = mem;
+		while (size > 0) 
+                {
+	                page = vmalloc_to_phys(memptr);
+			mem_map_reserve(MAP_NR(phys_to_virt(page)));
+			memptr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+	void *memptr;
+        unsigned long page;
+        
+	if (mem) 
+	{
+		memptr = mem;
+		while (size > 0) 
+                {
+	                page = vmalloc_to_phys(memptr);
+			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+			memptr += PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/*  Useful for using vmalloc()ed memory as DMA target  */
+static unsigned long vmalloc_to_bus(void *virt)
+{
+	pgd_t		*pgd;
+	pmd_t		*pmd;
+	pte_t		*pte;
+	unsigned long	a = (unsigned long)virt;
+
+	if (pgd_none(*(pgd = pgd_offset(current->mm, a))) ||
+	    pmd_none(*(pmd = pmd_offset(pgd,         a))) ||
+	    pte_none(*(pte = pte_offset(pmd,         a))))
+		return 0;
+	return virt_to_bus((void *)pte_page(*pte))
+		+ (a & (PAGE_SIZE - 1));
+}
+
+static unsigned long vmalloc_to_phys(void *virt) {
+	return virt_to_phys(bus_to_virt(vmalloc_to_bus(virt)));
+}
+
+/*
+ *	Create the giant waste of buffer space we need for now
+ *	until we get DMA to user space sorted out (probably 2.3.x)
+ *
+ *	We only create this as and when someone uses mmap
+ */
+ 
+static int fbuffer_alloc(struct planb *pb)
+{
+	if(!pb->fbuffer)
+		pb->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS
+					* PLANB_MAX_FBUF);
+	else
+		printk(KERN_ERR "PlanB: Double alloc of fbuffer!\n");
+	if(!pb->fbuffer)
+		return -ENOBUFS;
+	return 0;
+}
+
+/*****************************/
+/* Hardware access functions */
+/*****************************/
+
+static void saa_write_reg(unsigned char addr, unsigned char val)
+{
+	planb_regs->saa_addr = addr; eieio();
+	planb_regs->saa_regval = val; eieio();
+	return;
+}
+
+/* return  status byte 0 or 1: */
+static unsigned char saa_status(int byte, struct planb *pb)
+{
+	saa_regs[pb->win.norm][SAA7196_STDC] =
+		(saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1);
+	saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]);
+
+	/* Let's wait 30msec for this one */
+	current->state = TASK_INTERRUPTIBLE;
+#if LINUX_VERSION_CODE >= 0x02017F
+	schedule_timeout(30 * HZ / 1000);
+#else
+	current->timeout = jiffies + 30 * HZ / 1000;	/* 30 ms */;
+	schedule();
+#endif
+
+	return (unsigned char)in_8 (&planb_regs->saa_status);
+}
+
+static void saa_set(unsigned char addr, unsigned char val, struct planb *pb)
+{
+	if(saa_regs[pb->win.norm][addr] != val) {
+		saa_regs[pb->win.norm][addr] = val;
+		saa_write_reg (addr, val);
+	}
+	return;
+}
+
+static void saa_init_regs(struct planb *pb)
+{
+	int i;
+
+	for (i = 0; i < SAA7196_NUMREGS; i++)
+		saa_write_reg (i, saa_regs[pb->win.norm][i]);
+}
+
+static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,
+	struct planb *pb)
+{
+	int ht, norm = pb->win.norm;
+
+	switch(bpp) {
+	case 2:
+		/* RGB555+a 1x16-bit + 16-bit transparent */
+		saa_regs[norm][SAA7196_FMTS] &= ~0x3;
+		break;
+	case 1:
+	case 4:
+		/* RGB888 1x24-bit + 8-bit transparent */
+		saa_regs[norm][SAA7196_FMTS] &= ~0x1;
+		saa_regs[norm][SAA7196_FMTS] |= 0x2;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ht = (interlace ? height / 2 : height);
+	saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff);
+	saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3)
+						| (width >> 8 & 0x3);
+	saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff);
+	saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3)
+						| (ht >> 8 & 0x3);
+	/* feed both fields if interlaced, or else feed only even fields */
+	saa_regs[norm][SAA7196_FMTS] = (interlace) ?
+					(saa_regs[norm][SAA7196_FMTS] & ~0x60)
+					: (saa_regs[norm][SAA7196_FMTS] | 0x60);
+	/* transparent mode; extended format enabled */
+	saa_regs[norm][SAA7196_DPATH] |= 0x3;
+
+	return 0;
+}
+
+/***************************/
+/* DBDMA support functions */
+/***************************/
+
+static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch)
+{
+	out_le32(&ch->control, PLANB_CLR(RUN));
+	out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));
+}
+
+static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch)
+{
+	int i = 0;
+
+	out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH));
+	while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {
+		IDEBUG("PlanB: waiting for DMA to stop\n");
+		i++;
+	}
+}
+
+static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,
+	unsigned short command, unsigned int cmd_dep)
+{
+	st_le16(&ch->command, command);
+	st_le32(&ch->cmd_dep, cmd_dep);
+}
+
+static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,
+	unsigned int phy_addr, unsigned int cmd_dep)
+{
+	st_le16(&ch->command, STORE_WORD | KEY_SYSTEM);
+	st_le16(&ch->req_count, 4);
+	st_le32(&ch->phy_addr, phy_addr);
+	st_le32(&ch->cmd_dep, cmd_dep);
+}
+
+static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch,
+	unsigned short command, unsigned short req_count,
+	unsigned int phy_addr, unsigned int cmd_dep)
+{
+	st_le16(&ch->command, command);
+	st_le16(&ch->req_count, req_count);
+	st_le32(&ch->phy_addr, phy_addr);
+	st_le32(&ch->cmd_dep, cmd_dep);
+}
+
+static volatile struct dbdma_cmd *cmd_geo_setup(
+	volatile struct dbdma_cmd *c1, int width, int height, int interlace,
+	int bpp, int clip, struct planb *pb)
+{
+	int norm = pb->win.norm;
+
+	if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0)
+		return (volatile struct dbdma_cmd *)NULL;
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_FMTS);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_FMTS]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_DPATH);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_DPATH]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even),
+					bpp | ((clip)? PLANB_CLIPMASK: 0));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd),
+					bpp | ((clip)? PLANB_CLIPMASK: 0));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_OUTPIX);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_OUTPIX]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_HFILT);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_HFILT]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_OUTLINE);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_OUTLINE]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_VYP);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_VYP]);
+	return c1;
+}
+
+/******************************/
+/* misc. supporting functions */
+/******************************/
+
+static void __planb_wait(struct planb *pb)
+{
+	struct wait_queue wait = { current, NULL };
+
+	add_wait_queue(&pb->lockq, &wait);
+repeat:
+	current->state = TASK_UNINTERRUPTIBLE;
+	if (pb->lock) {
+		schedule();
+		goto repeat;
+	}
+	remove_wait_queue(&pb->lockq, &wait);
+	current->state = TASK_RUNNING;
+}
+
+static inline void planb_wait(struct planb *pb)
+{
+	DEBUG("PlanB: planb_wait\n");
+	if(pb->lock)
+		__planb_wait(pb);
+}
+
+static inline void planb_lock(struct planb *pb)
+{
+	DEBUG("PlanB: planb_lock\n");
+	if(pb->lock)
+		__planb_wait(pb);
+	pb->lock = 1;
+}
+
+static inline void planb_unlock(struct planb *pb)
+{
+	DEBUG("PlanB: planb_unlock\n");
+	pb->lock = 0;
+	wake_up(&pb->lockq);
+}
+
+/***************/
+/* Driver Core */
+/***************/
+
+static int planb_prepare_open(struct planb *pb)
+{
+	int	i, size;
+
+	/* allocate memory for two plus alpha command buffers (size: max lines,
+	   plus 40 commands handling, plus 1 alignment), plus dummy command buf,
+	   plus clipmask buffer, plus frame grabbing status */
+	size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS
+		* PLANB_DUMMY)*sizeof(struct dbdma_cmd)
+		+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
+		+MAX_GBUFFERS*sizeof(unsigned int);
+	if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+		return -ENOMEM;
+	memset ((void *) pb->priv_space, 0, size);
+	pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
+						DBDMA_ALIGN (pb->priv_space);
+	pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
+	pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);
+	pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;
+	pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;
+	for (i = 1; i < MAX_GBUFFERS; i++) {
+		pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;
+		pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;
+	}
+	pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]
+						+ PLANB_DUMMY);
+	pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
+
+	pb->fbuffer = (unsigned char *)rvmalloc(MAX_GBUFFERS * PLANB_MAX_FBUF);
+	if (!pb->fbuffer) {
+		kfree(pb->priv_space);
+		return -ENOMEM;
+	}
+	pb->grabbing = 0;
+	for (i = 0; i < MAX_GBUFFERS; i++) {
+		pb->frame_stat[i] = GBUFFER_UNUSED;
+		pb->gwidth[i] = 0;
+		pb->gheight[i] = 0;
+		pb->gfmt[i] = 0;
+		pb->gnorm_switch[i] = 0;
+#ifndef PLANB_GSCANLINE
+		pb->lsize[i] = 0;
+		pb->lnum[i] = 0;
+		pb->l_fr_addr[i]=(unsigned char *)rvmalloc(PAGE_SIZE*MAX_LNUM);
+		if (!pb->l_fr_addr[i]) {
+			int j;
+			kfree(pb->priv_space);
+			rvfree((void *)pb->fbuffer, MAX_GBUFFERS
+							* PLANB_MAX_FBUF);
+			for(j = 0; j < i; j++)
+				rvfree((void *)pb->l_fr_addr[j], PAGE_SIZE
+								* MAX_LNUM);
+			return -ENOMEM;
+		}
+#endif /* PLANB_GSCANLINE */
+	}
+	pb->gcount = 0;
+	pb->suspend = 0;
+	pb->last_fr = -999;
+	pb->prev_last_fr = -999;
+	return 0;   
+}
+
+static void planb_prepare_close(struct planb *pb)
+{
+#ifndef PLANB_GSCANLINE
+	int i;
+#endif
+
+	/* make sure the dma's are idle */
+	planb_dbdma_stop(&pb->planb_base->ch2);
+	planb_dbdma_stop(&pb->planb_base->ch1);
+	/* free kernel memory of command buffers */
+	if(pb->priv_space != 0) {
+		kfree (pb->priv_space);
+		pb->priv_space = 0;
+		pb->cmd_buff_inited = 0;
+	}
+	if(pb->fbuffer)
+		rvfree((void *)pb->fbuffer, MAX_GBUFFERS*PLANB_MAX_FBUF);
+	pb->fbuffer = NULL;
+#ifndef PLANB_GSCANLINE
+	for(i = 0; i < MAX_GBUFFERS; i++) {
+		if(pb->l_fr_addr[i])
+			rvfree((void *)pb->l_fr_addr[i], PAGE_SIZE * MAX_LNUM);
+		pb->l_fr_addr[i] = NULL;
+	}
+#endif /* PLANB_GSCANLINE */
+}
+
+/*****************************/
+/* overlay support functions */
+/*****************************/
+
+static void overlay_start(struct planb *pb)
+{
+
+	DEBUG("PlanB: overlay_start()\n");
+
+	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+
+		DEBUG("PlanB: presumably, grabbing is in progress...\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		out_le32 (&pb->planb_base->ch2.cmdptr,
+						virt_to_bus(pb->ch2_cmd));
+		planb_dbdma_restart(&pb->planb_base->ch2);
+		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+					DBDMA_NOP | BR_ALWAYS,
+					virt_to_bus(pb->ch1_cmd));
+		eieio();
+		pb->prev_last_fr = pb->last_fr;
+		pb->last_fr = -2;
+		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+			IDEBUG("PlanB: became inactive "
+				"in the mean time... reactivating\n");
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->ch1_cmd));
+			planb_dbdma_restart(&pb->planb_base->ch1);
+		}
+	} else {
+
+		DEBUG("PlanB: currently idle, so can do whatever\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		planb_dbdma_stop(&pb->planb_base->ch1);
+		st_le32 (&pb->planb_base->ch2.cmdptr,
+						virt_to_bus(pb->ch2_cmd));
+		st_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->ch1_cmd));
+		out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		planb_dbdma_restart(&pb->planb_base->ch2);
+		planb_dbdma_restart(&pb->planb_base->ch1);
+		pb->last_fr = -1;
+	}
+	return;
+}
+
+static void overlay_stop(struct planb *pb)
+{
+	DEBUG("PlanB: overlay_stop()\n");
+
+	if(pb->last_fr == -1) {
+
+		DEBUG("PlanB: no grabbing, it seems...\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		planb_dbdma_stop(&pb->planb_base->ch1);
+		pb->last_fr = -999;
+	} else if(pb->last_fr == -2) {
+		unsigned int cmd_dep;
+		tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
+		eieio();
+		cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
+		if(overlay_is_active(pb)) {
+
+			DEBUG("PlanB: overlay is currently active\n");
+
+			planb_dbdma_stop(&pb->planb_base->ch2);
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			if(cmd_dep != pb->ch1_cmd_phys) {
+				out_le32(&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->overlay_last1));
+				planb_dbdma_restart(&pb->planb_base->ch1);
+			}
+		}
+		pb->last_fr = pb->prev_last_fr;
+		pb->prev_last_fr = -999;
+	}
+	return;
+}
+
+static void suspend_overlay(struct planb *pb)
+{
+	int fr = -1;
+	struct dbdma_cmd last;
+
+	DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
+
+	if(pb->suspend++)
+		return;
+	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+		if(pb->last_fr == -2) {
+			fr = pb->prev_last_fr;
+			memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
+			tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+		}
+		if(overlay_is_active(pb)) {
+			planb_dbdma_stop(&pb->planb_base->ch2);
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			pb->suspended.overlay = 1;
+			pb->suspended.frame = fr;
+			memcpy(&pb->suspended.cmd, &last, sizeof(last));
+			return;
+		}
+	}
+	pb->suspended.overlay = 0;
+	pb->suspended.frame = fr;
+	memcpy(&pb->suspended.cmd, &last, sizeof(last));
+	return;
+}
+
+static void resume_overlay(struct planb *pb)
+{
+
+	DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
+
+	if(pb->suspend > 1)
+		return;
+	if(pb->suspended.frame != -1) {
+		memcpy((void*)pb->last_cmd[pb->suspended.frame],
+				&pb->suspended.cmd, sizeof(pb->suspended.cmd));
+	}
+	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+		goto finish;
+	}
+	if(pb->suspended.overlay) {
+
+		DEBUG("PlanB: overlay being resumed\n");
+
+		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
+		/* Set command buffer addresses */
+		st_le32(&pb->planb_base->ch1.cmdptr,
+					virt_to_bus(pb->overlay_last1));
+		out_le32(&pb->planb_base->ch2.cmdptr,
+					virt_to_bus(pb->overlay_last2));
+		/* Start the DMA controller */
+		out_le32 (&pb->planb_base->ch2.control,
+				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+		out_le32 (&pb->planb_base->ch1.control,
+				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+	} else if(pb->suspended.frame != -1) {
+		out_le32(&pb->planb_base->ch1.cmdptr,
+				virt_to_bus(pb->last_cmd[pb->suspended.frame]));
+		out_le32 (&pb->planb_base->ch1.control,
+				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+	}
+
+finish:
+	pb->suspend--;
+	wake_up_interruptible(&pb->suspendq);
+}
+
+static void add_clip(struct planb *pb, struct video_clip *clip) 
+{
+	volatile unsigned char	*base;
+	int	xc = clip->x, yc = clip->y;
+	int	wc = clip->width, hc = clip->height;
+	int	ww = pb->win.width, hw = pb->win.height;
+	int	x, y, xtmp1, xtmp2;
+
+	DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
+
+	if(xc < 0) {
+		wc += xc;
+		xc = 0;
+	}
+	if(yc < 0) {
+		hc += yc;
+		yc = 0;
+	}
+	if(xc + wc > ww)
+		wc = ww - xc;
+	if(wc <= 0) /* Nothing to do */
+		return;
+	if(yc + hc > hw)
+		hc = hw - yc;
+
+	for (y = yc; y < yc+hc; y++) {
+		xtmp1=xc>>3;
+		xtmp2=(xc+wc)>>3;
+		base = pb->mask + y*96;
+		if(xc != 0 || wc >= 8)
+			*(base + xtmp1) &= (unsigned char)(0x00ff &
+				(0xff00 >> (xc&7)));
+		for (x = xtmp1 + 1; x < xtmp2; x++) {
+			*(base + x) = 0;
+		}
+		if(xc < (ww & ~0x7))
+			*(base + xtmp2) &= (unsigned char)(0x00ff >>
+				((xc+wc) & 7));
+	}
+
+	return;
+}
+
+static void fill_cmd_buff(struct planb *pb)
+{
+	int restore = 0;
+	volatile struct dbdma_cmd last;
+
+	DEBUG("PlanB: fill_cmd_buff()\n");
+
+	if(pb->overlay_last1 != pb->ch1_cmd) {
+		restore = 1;
+		last = *(pb->overlay_last1);
+	}
+	memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
+					* sizeof(struct dbdma_cmd));
+	cmd_buff (pb);
+	if(restore)
+		*(pb->overlay_last1) = last;
+	if(pb->suspended.overlay) {
+		unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
+		if(jump_addr != pb->ch1_cmd_phys) {
+			int i;
+
+			DEBUG("PlanB: adjusting ch1's jump address\n");
+
+			for(i = 0; i < MAX_GBUFFERS; i++) {
+				if(pb->need_pre_capture[i]) {
+				    if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
+					goto found;
+				} else {
+				    if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
+					goto found;
+				}
+			}
+
+			DEBUG("PlanB: not found...\n");
+
+			goto out;
+found:
+			if(pb->need_pre_capture[i])
+				out_le32(&pb->pre_cmd[i]->phy_addr,
+						virt_to_bus(pb->overlay_last1));
+			else
+				out_le32(&pb->cap_cmd[i]->phy_addr,
+						virt_to_bus(pb->overlay_last1));
+		}
+	}
+out:
+	pb->cmd_buff_inited = 1;
+
+	return;
+}
+
+static void cmd_buff(struct planb *pb)
+{
+	int		i, bpp, count, nlines, stepsize, interlace;
+	unsigned long	base, jump, addr_com, addr_dep;
+	volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
+	volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
+
+	interlace = pb->win.interlace;
+	bpp = pb->win.bpp;
+	count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
+		(pb->win.swidth - pb->win.x) : pb->win.width));
+	nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
+		(pb->win.sheight - pb->win.y) : pb->win.height);
+
+	/* Do video in: */
+
+	/* Preamble commands: */
+	addr_com = virt_to_bus(c1);
+	addr_dep = virt_to_bus(&c1->cmd_dep);
+	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
+	jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
+	if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
+					bpp, 1, pb)) == NULL) {
+		printk(KERN_WARNING "PlanB: encountered serious problems\n");
+		tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
+		tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
+		return;
+	}
+	tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
+	tab_cmd_store(c1++, addr_dep, jump);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+							PLANB_SET(FIELD_SYNC));
+		/* (1) wait for field sync to be set */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
+		/* wait for field sync to be cleared */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+		/* if not odd field, wait until field sync is set again */
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
+		/* assert ch_sync to ch2 */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
+							PLANB_SET(CH_SYNC));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
+
+	base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
+					+ pb->win.pad) + pb->win.x * bpp);
+
+	if (interlace) {
+		stepsize = 2;
+		jump = virt_to_bus(c1 + (nlines + 1) / 2);
+	} else {
+		stepsize = 1;
+		jump = virt_to_bus(c1 + nlines);
+	}
+
+	/* even field data: */
+	for (i=0; i < nlines; i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
+			count, base + i * (pb->win.bpl + pb->win.pad), jump);
+
+	/* For non-interlaced, we use even fields only */
+	if (!interlace)
+		goto cmd_tab_data_end;
+
+	/* Resync to odd field */
+		/* (2) wait for field sync to be set */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
+		/* wait for field sync to be cleared */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+		/* if not odd field, wait until field sync is set again */
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
+		/* assert ch_sync to ch2 */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
+							PLANB_SET(CH_SYNC));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
+	
+	/* odd field data: */
+	jump = virt_to_bus(c1 + nlines / 2);
+	for (i=1; i < nlines; i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+			base + i * (pb->win.bpl + pb->win.pad), jump);
+
+	/* And jump back to the start */
+cmd_tab_data_end:
+	pb->overlay_last1 = c1;	/* keep a pointer to the last command */
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
+
+	/* Clipmask command buffer */
+
+	/* Preamble commands: */
+	tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
+							PLANB_SET(CH_SYNC));
+		/* wait until ch1 asserts ch_sync */
+	tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
+		/* clear ch_sync asserted by ch1 */
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
+							PLANB_CLR(CH_SYNC));
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
+							PLANB_SET(FIELD_SYNC));
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+							PLANB_SET(ODD_FIELD));
+
+	/* jump to end of even field if appropriate */
+	/* this points to (interlace)? pos. C: pos. B */
+	jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
+						virt_to_bus(c2 + nlines + 2);
+		/* if odd field, skip over to odd field clipmasking */
+	tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
+
+	/* even field mask: */
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+							PLANB_SET(DMA_ABORT));
+	/* this points to pos. B */
+	jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
+						virt_to_bus(c2 + nlines);
+	base = virt_to_bus(pb->mask);
+	for (i=0; i < nlines; i += stepsize, c2++)
+		tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
+			base + i * 96, jump);
+
+	/* For non-interlaced, we use only even fields */
+	if(!interlace)
+		goto cmd_tab_mask_end;
+
+	/* odd field mask: */
+/* C */	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+							PLANB_SET(DMA_ABORT));
+	/* this points to pos. B */
+	jump = virt_to_bus(c2 + nlines / 2);
+	base = virt_to_bus(pb->mask);
+	for (i=1; i < nlines; i += 2, c2++)     /* abort if set */
+		tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
+			base + i * 96, jump);
+
+	/* Inform channel 1 and jump back to start */
+cmd_tab_mask_end:
+	/* ok, I just realized this is kind of flawed. */
+	/* this part is reached only after odd field clipmasking. */
+	/* wanna clean up? */
+		/* wait for field sync to be set */
+		/* corresponds to fsync (1) of ch1 */
+/* B */	tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
+		/* restart ch1, meant to clear any dead bit or something */
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
+							PLANB_CLR(RUN));
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
+							PLANB_SET(RUN));
+	pb->overlay_last2 = c2;	/* keep a pointer to the last command */
+		/* start over even field clipmasking */
+	tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
+
+	eieio();
+	return;
+}
+
+/*********************************/
+/* grabdisplay support functions */
+/*********************************/
+
+static int palette2fmt[] = {
+       0,
+       PLANB_GRAY,
+       0,
+       0,
+       0,
+       PLANB_COLOUR32,
+       PLANB_COLOUR15,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+};
+#define PLANB_PALETTE_MAX 15
+
+#define SWAP4(x) (((x>>24) & 0x000000ff) |\
+                  ((x>>8)  & 0x0000ff00) |\
+                  ((x<<8)  & 0x00ff0000) |\
+                  ((x<<24) & 0xff000000))
+
+static inline int overlay_is_active(struct planb *pb)
+{
+	unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
+	unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
+
+	return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
+			&& (caddr < (pb->ch1_cmd_phys + size))
+			&& (caddr >= (unsigned)pb->ch1_cmd_phys);
+}
+
+static int vgrab(struct planb *pb, struct video_mmap *mp)
+{
+	unsigned int fr = mp->frame;
+	unsigned int format;
+
+	if(pb->fbuffer==NULL) {
+		if(fbuffer_alloc(pb))
+			return -ENOBUFS;
+	}
+
+	IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
+						mp->width, mp->height, fr);
+
+	if(pb->grabbing >= MAX_GBUFFERS)
+		return -ENOBUFS;
+	if(fr > (MAX_GBUFFERS - 1) || fr < 0)
+		return -EINVAL;
+	if(mp->height <= 0 || mp->width <= 0)
+		return -EINVAL;
+	if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
+		return -EINVAL;
+	if((format = palette2fmt[mp->format]) == 0)
+		return -EINVAL;
+	if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
+		return -EINVAL;
+
+	planb_lock(pb);
+	pb->gbuffer[fr] = (unsigned char *)(pb->fbuffer + PLANB_MAX_FBUF * fr);
+	if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
+			format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
+#ifdef PLANB_GSCANLINE
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 13'
echo 'File patch-2.2.8 is continued in part 14'
echo 14 > _shar_seq_.tmp
#!/bin/sh
# this is part 14 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 14; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+		int i;
+#else
+		unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
+								* pb->gfmt[fr];
+		unsigned int nsize = mp->width * mp->height * format;
+#endif
+
+		IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
+					mp->width, mp->height, mp->format);
+
+#ifndef PLANB_GSCANLINE
+		if(pb->gnorm_switch[fr])
+			nsize = 0;
+		if(nsize < osize)
+			memset((void *)(pb->gbuffer[fr] + nsize), 0,
+								osize - nsize);
+		memset((void *)pb->l_fr_addr[fr], 0, PAGE_SIZE * pb->lnum[fr]);
+#else
+/* XXX TODO */
+/*
+		if(pb->gnorm_switch[fr])
+			memset((void *)pb->gbuffer[fr], 0,
+					pb->gbytes_per_line * pb->gheight[fr]);
+		else {
+			if(mp->
+			for(i = 0; i < pb->gheight[fr]; i++) {
+				memset((void *)(pb->gbuffer[fr]
+					+ pb->gbytes_per_line * i
+			}
+		}
+*/
+#endif
+		pb->gwidth[fr] = mp->width;
+		pb->gheight[fr] = mp->height;
+		pb->gfmt[fr] = format;
+		pb->last_cmd[fr] = setup_grab_cmd(fr, pb);
+		planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */
+		pb->need_pre_capture[fr] = 1;
+		pb->gnorm_switch[fr] = 0;
+	} else
+		pb->need_pre_capture[fr] = 0;
+	pb->frame_stat[fr] = GBUFFER_GRABBING;
+	if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+
+		IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch1);
+		if(pb->need_pre_capture[fr]) {
+
+			IDEBUG("PlanB: padding pre-capture sequence\n");
+
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->pre_cmd[fr]));
+		} else {
+			tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+			tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+		/* let's be on the safe side. here is not timing critical. */
+			tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0);
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->cap_cmd[fr]));
+		}
+		planb_dbdma_restart(&pb->planb_base->ch1);
+		pb->last_fr = fr;
+	} else {
+		int i;
+
+		IDEBUG("PlanB: ch1 active, grabbing being queued\n");
+
+		if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
+						overlay_is_active(pb))) {
+
+			IDEBUG("PlanB: overlay is active, grabbing defered\n");
+
+			tab_cmd_dbdma(pb->last_cmd[fr],
+					DBDMA_NOP | BR_ALWAYS,
+					virt_to_bus(pb->ch1_cmd));
+			if(pb->need_pre_capture[fr]) {
+
+				IDEBUG("PlanB: padding pre-capture sequence\n");
+
+				tab_cmd_store(pb->pre_cmd[fr],
+				    virt_to_bus(&pb->overlay_last1->cmd_dep),
+						virt_to_bus(pb->ch1_cmd));
+				eieio();
+				out_le32 (&pb->overlay_last1->cmd_dep,
+						virt_to_bus(pb->pre_cmd[fr]));
+			} else {
+				tab_cmd_store(pb->cap_cmd[fr],
+				    virt_to_bus(&pb->overlay_last1->cmd_dep),
+						virt_to_bus(pb->ch1_cmd));
+				tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+								DBDMA_NOP, 0);
+				eieio();
+				out_le32 (&pb->overlay_last1->cmd_dep,
+						virt_to_bus(pb->cap_cmd[fr]));
+			}
+			for(i = 0; overlay_is_active(pb) && i < 999; i++)
+				IDEBUG("PlanB: waiting for overlay done\n");
+			tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
+			pb->prev_last_fr = fr;
+			pb->last_fr = -2;
+		} else if(pb->last_fr == -2) {
+
+			IDEBUG("PlanB: mixed mode detected, grabbing"
+				" will be done before activating overlay\n");
+
+			tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
+			if(pb->need_pre_capture[fr]) {
+
+				IDEBUG("PlanB: padding pre-capture sequence\n");
+
+				tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->pre_cmd[fr]));
+				eieio();
+			} else {
+				tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+				if(pb->gwidth[pb->prev_last_fr] !=
+								pb->gwidth[fr]
+					|| pb->gheight[pb->prev_last_fr] !=
+								pb->gheight[fr]
+					|| pb->gfmt[pb->prev_last_fr] !=
+								pb->gfmt[fr])
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+								DBDMA_NOP, 0);
+				else
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+					    DBDMA_NOP | BR_ALWAYS,
+					    virt_to_bus(pb->cap_cmd[fr] + 16));
+				tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->cap_cmd[fr]));
+				eieio();
+			}
+			tab_cmd_dbdma(pb->last_cmd[fr],
+					DBDMA_NOP | BR_ALWAYS,
+					virt_to_bus(pb->ch1_cmd));
+			eieio();
+ pb->prev_last_fr = fr;
+			pb->last_fr = -2;
+		} else {
+
+			IDEBUG("PlanB: active grabbing session detected\n");
+
+			if(pb->need_pre_capture[fr]) {
+
+				IDEBUG("PlanB: padding pre-capture sequence\n");
+
+				tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->pre_cmd[fr]));
+				eieio();
+			} else {
+				tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+				tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+				if(pb->gwidth[pb->last_fr] != pb->gwidth[fr]
+					|| pb->gheight[pb->last_fr] !=
+								pb->gheight[fr]
+					|| pb->gfmt[pb->last_fr] !=
+								pb->gfmt[fr])
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+								DBDMA_NOP, 0);
+				else
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+					    DBDMA_NOP | BR_ALWAYS,
+					    virt_to_bus(pb->cap_cmd[fr] + 16));
+				tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->cap_cmd[fr]));
+				eieio();
+			}
+			pb->last_fr = fr;
+		}
+		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+
+			IDEBUG("PlanB: became inactive in the mean time..."
+				"reactivating\n");
+
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+ virt_to_bus(pb->cap_cmd[fr]));
+			planb_dbdma_restart(&pb->planb_base->ch1);
+		}
+	}
+	pb->grabbing++;
+	planb_unlock(pb);
+
+	return 0;
+}
+
+static void planb_pre_capture(int fr, int bpp, struct planb *pb)
+{
+	volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
+	int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
+
+	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
+	if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
+						bpp, 0, pb)) == NULL) {
+		printk(KERN_WARNING "PlanB: encountered some problems\n");
+		tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0);
+		return;
+	}
+	/* Sync to even field */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+		PLANB_SET(FIELD_SYNC));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
+ tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+ PLANB_SET(DMA_ABORT));
+	/* For non-interlaced, we use even fields only */
+	if (pb->gheight[fr] <= pb->maxlines/2)
+		goto cmd_tab_data_end;
+	/* Sync to odd field */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(DMA_ABORT));
+cmd_tab_data_end:
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
+
+	eieio();
+}
+
+static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
+{
+	int		i, bpp, count, nlines, stepsize, interlace;
+#ifdef PLANB_GSCANLINE
+	int		scanline;
+#else
+	int		nlpp, leftover1;
+	unsigned long	base;
+#endif
+	unsigned long	jump;
+	unsigned char	*vaddr;
+	volatile struct dbdma_cmd *c1;
+	volatile struct dbdma_cmd *jump_addr;
+
+	c1 = pb->cap_cmd[fr];
+	interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
+	bpp = pb->gfmt[fr];	/* gfmt = bpp */
+	count = bpp * pb->gwidth[fr];
+	nlines = pb->gheight[fr];
+#ifdef PLANB_GSCANLINE
+	scanline = pb->gbytes_per_line;
+#else
+	pb->lsize[fr] = count;
+	pb->lnum[fr] = 0;
+#endif
+
+	/* Do video in: */
+
+	/* Preamble commands: */
+	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++;
+	if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
+						bpp, 0, pb)) == NULL) {
+		printk(KERN_WARNING "PlanB: encountered serious problems\n");
+		tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0);
+		return (pb->cap_cmd[fr] + 2);
+	}
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+		PLANB_SET(FIELD_SYNC));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
+ tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+ PLANB_SET(DMA_ABORT));
+
+	if (interlace) {
+		stepsize = 2;
+ jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2;
+	} else {
+		stepsize = 1;
+		jump_addr = c1 + TAB_FACTOR * nlines;
+	}
+	jump = virt_to_bus(jump_addr);
+
+	/* even field data: */
+
+	vaddr = pb->gbuffer[fr];
+#ifdef PLANB_GSCANLINE
+	for (i = 0; i < nlines; i += stepsize) {
+		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(vaddr + i * scanline), jump);
+	}
+#else
+	i = 0;
+	leftover1 = 0;
+	do {
+	    int j;
+
+	    base = vmalloc_to_bus((void*)vaddr);
+	    nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
+	    for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
+			  count, base + count * j * stepsize + leftover1, jump);
+	    if(i < nlines) {
+		int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
+
+		if(lov0 == 0)
+		    leftover1 = 0;
+		else {
+		    if(lov0 >= count) {
+			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
+				+ count * nlpp * stepsize + leftover1, jump);
+		    } else {
+			pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count * nlpp
+							* stepsize + leftover1;
+			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE
+							* pb->lnum[fr]), jump);
+			if(++pb->lnum[fr] > MAX_LNUM)
+				pb->lnum[fr]--;
+		    }
+		    leftover1 = count * stepsize - lov0;
+		    i += stepsize;
+		}
+	    }
+	    vaddr += PAGE_SIZE;
+	} while(i < nlines);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
+	c1 = jump_addr;
+#endif /* PLANB_GSCANLINE */
+
+	/* For non-interlaced, we use even fields only */
+	if (!interlace)
+		goto cmd_tab_data_end;
+
+ /* Sync to odd field */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(DMA_ABORT));
+	
+	/* odd field data: */
+	jump_addr = c1 + TAB_FACTOR * nlines / 2;
+	jump = virt_to_bus(jump_addr);
+#ifdef PLANB_GSCANLINE
+	for (i = 1; i < nlines; i += stepsize) {
+		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(vaddr + i * scanline), jump);
+	}
+#else
+	i = 1;
+	leftover1 = 0;
+	vaddr = pb->gbuffer[fr];
+	if(nlines <= 1)
+	    goto skip;
+	do {
+	    int j;
+
+	    base = vmalloc_to_bus((void*)vaddr);
+	    nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
+	    if(leftover1 >= count) {
+		tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+						base + leftover1 - count, jump);
+		i += stepsize;
+	    }
+	    for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+			base + count * (j * stepsize + 1) + leftover1, jump);
+	    if(i < nlines) {
+		int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
+
+		if(lov0 == 0)
+		    leftover1 = 0;
+		else {
+		    if(lov0 > count) {
+			pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count
+					* (nlpp * stepsize + 1) + leftover1;
+			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE
+							* pb->lnum[fr]), jump);
+			if(++pb->lnum[fr] > MAX_LNUM)
+				pb->lnum[fr]--;
+			i += stepsize;
+		    }
+		    leftover1 = count * stepsize - lov0;
+		}
+	    }
+	    vaddr += PAGE_SIZE;
+	} while(i < nlines);
+skip:
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
+	c1 = jump_addr;
+#endif /* PLANB_GSCANLINE */
+
+cmd_tab_data_end:
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
+			(fr << 2) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
+	/* stop it */
+	tab_cmd_dbdma(c1, DBDMA_STOP, 0);
+
+	eieio();
+	return c1;
+}
+
+static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned int stat, astat;
+	struct planb *pb = (struct planb *)dev_id;
+
+	IDEBUG("PlanB: planb_irq()\n");
+
+	/* get/clear interrupt status bits */
+	stat = in_le32(&pb->planb_base->intr_stat);
+	astat = stat & pb->intr_mask;
+	out_le32(&pb->planb_base->intr_stat, PLANB_IRQ_CMD_MASK
+					& ~astat & stat & ~PLANB_GEN_IRQ);
+
+	if(astat & PLANB_FRM_IRQ) {
+		unsigned int fr = stat >> 2;
+#ifndef PLANB_GSCANLINE
+		int i;
+#endif
+		IDEBUG("PlanB: PLANB_FRM_IRQ\n");
+
+		pb->gcount++;
+
+		IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
+				pb->grabbing, fr, pb->gcount);
+#ifndef PLANB_GSCANLINE
+		IDEBUG("PlanB: %d * %d bytes are being copied over\n",
+				pb->lnum[fr], pb->lsize[fr]);
+		for(i = 0; i < pb->lnum[fr]; i++)
+			memcpy(pb->l_to_addr[fr][i], pb->l_fr_addr[fr]
+					+ PAGE_SIZE * i, pb->lsize[fr]);
+#endif
+		pb->frame_stat[fr] = GBUFFER_DONE;
+		pb->grabbing--;
+		wake_up_interruptible(&pb->capq);
+		return;
+	}
+	/* incorrect interrupts? */
+	pb->intr_mask = PLANB_CLR_IRQ;
+	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+	printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
+							" unconditionally\n");
+}
+
+/*******************************
+ * Device Operations functions *
+ *******************************/
+
+static int planb_open(struct video_device *dev, int mode)
+{
+	struct planb *pb = (struct planb *)dev;
+
+	if (pb->user == 0) {
+		int err;
+		if((err = planb_prepare_open(pb)) != 0)
+			return err;
+	}
+	pb->user++;
+
+	DEBUG("PlanB: device opened\n");
+
+	MOD_INC_USE_COUNT;
+	return 0;   
+}
+
+static void planb_close(struct video_device *dev)
+{
+	struct planb *pb = (struct planb *)dev;
+
+	if(pb->user < 1) /* ??? */
+		return;
+	planb_lock(pb);
+	if (pb->user == 1) {
+		if (pb->overlay) {
+			planb_dbdma_stop(&pb->planb_base->ch2);
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			pb->overlay = 0;
+		}
+		planb_prepare_close(pb);
+	}
+	pb->user--;
+	planb_unlock(pb);
+
+	DEBUG("PlanB: device closed\n");
+
+	MOD_DEC_USE_COUNT;  
+}
+
+static long planb_read(struct video_device *v, char *buf, unsigned long count,
+				int nonblock)
+{
+	DEBUG("planb: read request\n");
+	return -EINVAL;
+}
+
+static long planb_write(struct video_device *v, const char *buf,
+				unsigned long count, int nonblock)
+{
+	DEBUG("planb: write request\n");
+	return -EINVAL;
+}
+
+static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct planb *pb=(struct planb *)dev;
+  	
+	switch (cmd)
+	{	
+		case VIDIOCGCAP:
+		{
+			struct video_capability b;
+
+			DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
+
+			strcpy (b.name, pb->video_dev.name);
+			b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
+				 VID_TYPE_FRAMERAM | VID_TYPE_SCALES |
+				 VID_TYPE_CAPTURE;
+			b.channels = 2;	/* composite & svhs */
+			b.audios = 0;
+			b.maxwidth = PLANB_MAXPIXELS;
+                        b.maxheight = PLANB_MAXLINES;
+                        b.minwidth = 32; /* wild guess */
+                        b.minheight = 32;
+                        if (copy_to_user(arg,&b,sizeof(b)))
+                                return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSFBUF:
+		{
+                        struct video_buffer v;
+			unsigned short bpp;
+			unsigned int fmt;
+
+			DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
+
+                        if (!capable(CAP_SYS_ADMIN))
+                                return -EPERM;
+                        if (copy_from_user(&v, arg,sizeof(v)))
+                                return -EFAULT;
+			planb_lock(pb);
+			switch(v.depth) {
+			case 8:
+				bpp = 1;
+				fmt = PLANB_GRAY;
+				break;
+			case 15:
+			case 16:
+				bpp = 2;
+				fmt = PLANB_COLOUR15;
+				break;
+			case 24:
+			case 32:
+				bpp = 4;
+				fmt = PLANB_COLOUR32;
+				break;
+			default:
+				planb_unlock(pb);
+                                return -EINVAL;
+			}
+			if (bpp * v.width > v.bytesperline) {
+				planb_unlock(pb);
+				return -EINVAL;
+			}
+			pb->win.bpp = bpp;
+			pb->win.color_fmt = fmt;
+			pb->frame_buffer_phys = (unsigned long) v.base;
+			pb->win.sheight = v.height;
+			pb->win.swidth = v.width;
+			pb->picture.depth = pb->win.depth = v.depth;
+			pb->win.bpl = pb->win.bpp * pb->win.swidth;
+			pb->win.pad = v.bytesperline - pb->win.bpl;
+
+                        DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
+				" bpl %d (+ %d)\n", v.base, v.width,v.height,
+				pb->win.bpp, pb->win.bpl, pb->win.pad);
+
+			pb->cmd_buff_inited = 0;
+			if(pb->overlay) {
+				suspend_overlay(pb);
+				fill_cmd_buff(pb);
+				resume_overlay(pb);
+			}
+			planb_unlock(pb);
+			return 0;		
+		}
+		case VIDIOCGFBUF:
+		{
+                        struct video_buffer v;
+
+			DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
+
+			v.base = (void *)pb->frame_buffer_phys;
+			v.height = pb->win.sheight;
+			v.width = pb->win.swidth;
+			v.depth = pb->win.depth;
+			v.bytesperline = pb->win.bpl + pb->win.pad;
+			if (copy_to_user(arg, &v, sizeof(v)))
+                                return -EFAULT;
+			return 0;
+		}
+		case VIDIOCCAPTURE:
+		{
+			int i;
+
+                        if(copy_from_user(&i, arg, sizeof(i)))
+                                return -EFAULT;
+			if(i==0) {
+				DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
+
+				if (!(pb->overlay))
+					return 0;
+				planb_lock(pb);
+				pb->overlay = 0;
+				overlay_stop(pb);
+				planb_unlock(pb);
+			} else {
+				DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
+
+				if (pb->frame_buffer_phys == 0 ||
+					  pb->win.width == 0 ||
+					  pb->win.height == 0)
+					return -EINVAL;
+				if (pb->overlay)
+					return 0;
+				planb_lock(pb);
+				pb->overlay = 1;
+				if(!(pb->cmd_buff_inited))
+					fill_cmd_buff(pb);
+				overlay_start(pb);
+				planb_unlock(pb);
+			}
+			return 0;
+		}
+		case VIDIOCGCHAN:
+		{
+			struct video_channel v;
+
+			DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
+
+			if(copy_from_user(&v, arg,sizeof(v)))
+				return -EFAULT;
+			v.flags = 0;
+			v.tuners = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = pb->win.norm;
+			switch(v.channel)
+			{
+			case 0:
+				strcpy(v.name,"Composite");
+				break;
+			case 1:
+ strcpy(v.name,"SVHS");
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+
+			return 0;
+		}
+		case VIDIOCSCHAN:
+		{
+			struct video_channel v;
+
+			DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
+
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+
+			if (v.norm != pb->win.norm) {
+				int i, maxlines;
+
+				switch (v.norm)
+				{
+				case VIDEO_MODE_PAL:
+				case VIDEO_MODE_SECAM:
+					maxlines = PLANB_MAXLINES;
+					break;
+				case VIDEO_MODE_NTSC:
+					maxlines = PLANB_NTSC_MAXLINES;
+					break;
+				default:
+					return -EINVAL;
+					break;
+				}
+				planb_lock(pb);
+				/* empty the grabbing queue */
+				while(pb->grabbing)
+					interruptible_sleep_on(&pb->capq);
+				pb->maxlines = maxlines;
+				pb->win.norm = v.norm;
+				/* Stop overlay if running */
+				suspend_overlay(pb);
+				for(i = 0; i < MAX_GBUFFERS; i++)
+					pb->gnorm_switch[i] = 1;
+				/* I know it's an overkill, but.... */
+				fill_cmd_buff(pb);
+				/* ok, now init it accordingly */
+				saa_init_regs (pb);
+				/* restart overlay if it was running */
+				resume_overlay(pb);
+				planb_unlock(pb);
+			}
+
+			switch(v.channel)
+			{
+			case 0:	/* Composite	*/
+				saa_set (SAA7196_IOCC,
+					((saa_regs[pb->win.norm][SAA7196_IOCC] &
+					  ~7) | 3), pb);
+				break;
+			case 1:	/* SVHS		*/
+				saa_set (SAA7196_IOCC,
+					((saa_regs[pb->win.norm][SAA7196_IOCC] &
+					  ~7) | 4), pb);
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+
+			return 0;
+		}
+		case VIDIOCGPICT:
+		{
+			struct video_picture vp = pb->picture;
+
+			DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
+
+			switch(pb->win.color_fmt) {
+			case PLANB_GRAY:
+				vp.palette = VIDEO_PALETTE_GREY;
+			case PLANB_COLOUR15:
+				vp.palette = VIDEO_PALETTE_RGB555;
+				break;
+			case PLANB_COLOUR32:
+				vp.palette = VIDEO_PALETTE_RGB32;
+				break;
+			default:
+				vp.palette = 0;
+				break;
+			}
+
+			if(copy_to_user(arg,&vp,sizeof(vp)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSPICT:
+		{
+			struct video_picture vp;
+
+			DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
+
+			if(copy_from_user(&vp,arg,sizeof(vp)))
+				return -EFAULT;
+			pb->picture = vp;
+			/* Should we do sanity checks here? */
+			saa_set (SAA7196_BRIG, (unsigned char)
+			    ((pb->picture.brightness) >> 8), pb);
+			saa_set (SAA7196_HUEC, (unsigned char)
+			    ((pb->picture.hue) >> 8) ^ 0x80, pb);
+			saa_set (SAA7196_CSAT, (unsigned char)
+			    ((pb->picture.colour) >> 9), pb);
+			saa_set (SAA7196_CONT, (unsigned char)
+			    ((pb->picture.contrast) >> 9), pb);
+
+			return 0;
+		}
+		case VIDIOCSWIN:
+		{
+			struct video_window	vw;
+			struct video_clip	clip;
+			int 			i;
+			
+			DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
+
+			if(copy_from_user(&vw,arg,sizeof(vw)))
+				return -EFAULT;
+
+			planb_lock(pb);
+			/* Stop overlay if running */
+			suspend_overlay(pb);
+			pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
+			if (pb->win.x != vw.x ||
+			    pb->win.y != vw.y ||
+			    pb->win.width != vw.width ||
+			    pb->win.height != vw.height ||
+			    !pb->cmd_buff_inited) {
+				pb->win.x = vw.x;
+				pb->win.y = vw.y;
+				pb->win.width = vw.width;
+				pb->win.height = vw.height;
+				fill_cmd_buff(pb);
+			}
+			/* Reset clip mask */
+			memset ((void *) pb->mask, 0xff, (pb->maxlines
+					* ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
+			/* Add any clip rects */
+			for (i = 0; i < vw.clipcount; i++) {
+				if (copy_from_user(&clip, vw.clips + i,
+						sizeof(struct video_clip)))
+					return -EFAULT;
+				add_clip(pb, &clip);
+			}
+			/* restart overlay if it was running */
+			resume_overlay(pb);
+			planb_unlock(pb);
+			return 0;
+		}
+		case VIDIOCGWIN:
+		{
+			struct video_window vw;
+
+			DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
+
+			vw.x=pb->win.x;
+			vw.y=pb->win.y;
+			vw.width=pb->win.width;
+			vw.height=pb->win.height;
+			vw.chromakey=0;
+			vw.flags=0;
+			if(pb->win.interlace)
+				vw.flags|=VIDEO_WINDOW_INTERLACE;
+			if(copy_to_user(arg,&vw,sizeof(vw)))
+				return -EFAULT;
+			return 0;
+		}
+	        case VIDIOCSYNC: {
+			int i;
+
+			IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
+
+			if(copy_from_user((void *)&i,arg,sizeof(int)))
+				return -EFAULT;
+
+			IDEBUG("PlanB: sync to frame %d\n", i);
+
+                        if(i > (MAX_GBUFFERS - 1) || i < 0)
+                                return -EINVAL;
+chk_grab:
+                        switch (pb->frame_stat[i]) {
+                        case GBUFFER_UNUSED:
+                                return -EINVAL;
+			case GBUFFER_GRABBING:
+				IDEBUG("PlanB: waiting for grab"
+							" done (%d)\n", i);
+ 			        interruptible_sleep_on(&pb->capq);
+				goto chk_grab;
+                        case GBUFFER_DONE:
+                                pb->frame_stat[i] = GBUFFER_UNUSED;
+ break;
+                        }
+                        return 0;
+		}
+
+	        case VIDIOCMCAPTURE:
+		{
+                        struct video_mmap vm;
+			volatile unsigned int status;
+
+			IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
+
+			if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
+				return -EFAULT;
+                        status = pb->frame_stat[vm.frame];
+                        if (status != GBUFFER_UNUSED)
+                                return -EBUSY;
+
+		        return vgrab(pb, &vm);
+		}
+		
+		case VIDIOCGMBUF:
+		{
+			int i;
+			struct video_mbuf vm;
+
+			DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
+
+			memset(&vm, 0 , sizeof(vm));
+			vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
+			vm.frames = MAX_GBUFFERS;
+			for(i = 0; i<MAX_GBUFFERS; i++)
+				vm.offsets[i] = PLANB_MAX_FBUF * i;
+			if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+				return -EFAULT;
+			return 0;
+		}
+		
+		case PLANBIOCGSAAREGS:
+		{
+			struct planb_saa_regs preg;
+
+			DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
+
+			if(copy_from_user(&preg, arg, sizeof(preg)))
+				return -EFAULT;
+			if(preg.addr >= SAA7196_NUMREGS)
+				return -EINVAL;
+			preg.val = saa_regs[pb->win.norm][preg.addr];
+			if(copy_to_user((void *)arg, (void *)&preg,
+								sizeof(preg)))
+				return -EFAULT;
+			return 0;
+		}
+		
+		case PLANBIOCSSAAREGS:
+		{
+			struct planb_saa_regs preg;
+
+			DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
+
+			if(copy_from_user(&preg, arg, sizeof(preg)))
+				return -EFAULT;
+			if(preg.addr >= SAA7196_NUMREGS)
+				return -EINVAL;
+			saa_set (preg.addr, preg.val, pb);
+			return 0;
+		}
+		
+		case PLANBIOCGSTAT:
+		{
+			struct planb_stat_regs pstat;
+
+			DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
+
+			pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
+			pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
+			pstat.saa_stat0 = saa_status(0, pb);
+			pstat.saa_stat1 = saa_status(1, pb);
+
+			if(copy_to_user((void *)arg, (void *)&pstat,
+							sizeof(pstat)))
+				return -EFAULT;
+			return 0;
+		}
+		
+		case PLANBIOCSMODE: {
+			int v;
+
+			DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
+
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+
+			switch(v)
+			{
+			case PLANB_TV_MODE:
+				saa_set (SAA7196_STDC,
+					(saa_regs[pb->win.norm][SAA7196_STDC] &
+					  0x7f), pb);
+				break;
+			case PLANB_VTR_MODE:
+				saa_set (SAA7196_STDC,
+					(saa_regs[pb->win.norm][SAA7196_STDC] |
+ 0x80), pb);
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+			pb->win.mode = v;
+			return 0;
+		}
+		case PLANBIOCGMODE: {
+			int v=pb->win.mode;
+
+			DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
+
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+#ifdef PLANB_GSCANLINE
+		case PLANBG_GRAB_BPL: {
+			int v=pb->gbytes_per_line;
+
+			DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
+
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+#endif /* PLANB_GSCANLINE */
+		case PLANB_INTR_DEBUG: {
+			int i;
+
+			DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
+
+			if(copy_from_user(&i, arg, sizeof(i)))
+				return -EFAULT;
+
+			/* avoid hang ups all together */
+			for (i = 0; i < MAX_GBUFFERS; i++) {
+				if(pb->frame_stat[i] == GBUFFER_GRABBING) {
+					pb->frame_stat[i] = GBUFFER_DONE;
+				}
+			}
+			if(pb->grabbing)
+				pb->grabbing--;
+			wake_up_interruptible(&pb->capq);
+			return 0;
+		}
+		case PLANB_INV_REGS: {
+			int i;
+			struct planb_any_regs any;
+
+			DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
+
+			if(copy_from_user(&any, arg, sizeof(any)))
+				return -EFAULT;
+			if(any.offset < 0 || any.offset + any.bytes > 0x400)
+				return -EINVAL;
+			if(any.bytes > 128)
+				return -EINVAL;
+			for (i = 0; i < any.bytes; i++) {
+				any.data[i] =
+					in_8((unsigned char *)pb->planb_base
+							+ any.offset + i);
+			}
+			if(copy_to_user(arg,&any,sizeof(any)))
+				return -EFAULT;
+			return 0;
+		}
+		default:
+		{
+			DEBUG("PlanB: Unimplemented IOCTL\n");
+			return -ENOIOCTLCMD;
+		}
+	/* Some IOCTLs are currently unsupported on PlanB */
+		case VIDIOCGTUNER: {
+		DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
+			goto unimplemented; }
+		case VIDIOCSTUNER: {
+		DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
+			goto unimplemented; }
+		case VIDIOCSFREQ: {
+		DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
+			goto unimplemented; }
+		case VIDIOCGFREQ: {
+		DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
+			goto unimplemented; }
+		case VIDIOCKEY: {
+		DEBUG("PlanB: IOCTL VIDIOCKEY\n");
+			goto unimplemented; }
+		case VIDIOCSAUDIO: {
+		DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
+			goto unimplemented; }
+		case VIDIOCGAUDIO: {
+		DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
+			goto unimplemented; }
+unimplemented:
+		DEBUG("       Unimplemented\n");
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/*
+ *	This maps the vmalloced and reserved fbuffer to user space.
+ *
+ *  FIXME: 
+ *  - PAGE_READONLY should suffice!?
+ *  - remap_page_range is kind of inefficient for page by page remapping.
+ *    But e.g. pte_alloc() does not work in modules ... :-(
+ */
+ 
+static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct planb *pb=(struct planb *)dev;
+        unsigned long start=(unsigned long) adr;
+	unsigned long page;
+	void *pos;
+
+	if (size>MAX_GBUFFERS*PLANB_MAX_FBUF)
+	        return -EINVAL;
+	if (!pb->fbuffer)
+	{
+		if(fbuffer_alloc(pb))
+			return -EINVAL;
+	}
+	pos = (void *)pb->fbuffer;
+	while (size > 0) 
+	{
+	        page = vmalloc_to_phys(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		        return -EAGAIN;
+		start+=PAGE_SIZE;
+		pos+=PAGE_SIZE;
+		size-=PAGE_SIZE;    
+	}
+	return 0;
+}
+
+/* This gets called upon device registration */
+/* we could do some init here */
+static int planb_init_done(struct video_device *dev)
+{
+	return 0;
+}
+
+static struct video_device planb_template=
+{
+	PLANB_DEVICE_NAME,
+	VID_TYPE_OVERLAY,
+	VID_HARDWARE_PLANB,
+	planb_open,
+	planb_close,
+	planb_read,
+	planb_write,
+#if LINUX_VERSION_CODE >= 0x020100
+	NULL,	/* poll */
+#endif
+	planb_ioctl,
+	planb_mmap,	/* mmap? */
+	planb_init_done,
+	NULL,	/* pointer to private data */
+	0,
+	0
+};
+
+static int init_planb(struct planb *pb)
+{
+	unsigned char saa_rev;
+	int i, result;
+
+	memset ((void *) &pb->win, 0, sizeof (struct planb_window));
+	/* Simple sanity check */
+	if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
+		printk(KERN_ERR "PlanB: Option(s) invalid\n");
+		return -2;
+	}
+	pb->win.norm = def_norm;
+	pb->win.mode = PLANB_TV_MODE;	/* TV mode */
+	pb->win.interlace=1;
+	pb->win.x=0;
+	pb->win.y=0;
+	pb->win.width=768; /* 640 */
+	pb->win.height=576; /* 480 */
+	pb->maxlines=576;
+#if 0
+	btv->win.cropwidth=768; /* 640 */
+	btv->win.cropheight=576; /* 480 */
+	btv->win.cropx=0;
+	btv->win.cropy=0;
+#endif
+	pb->win.pad=0;
+	pb->win.bpp=4;
+	pb->win.depth=32;
+	pb->win.color_fmt=PLANB_COLOUR32;
+	pb->win.bpl=1024*pb->win.bpp;
+	pb->win.swidth=1024;
+	pb->win.sheight=768;
+#ifdef PLANB_GSCANLINE
+	if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
+				|| (pb->gbytes_per_line <= 0))
+		return -3;
+	else {
+		/* page align pb->gbytes_per_line for DMA purpose */
+		for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
+			i>>=1;
+		pb->gbytes_per_line = i;
+	}
+#endif
+	pb->tab_size = PLANB_MAXLINES + 40;
+	pb->suspend = 0;
+	pb->lock = 0;
+	pb->lockq = NULL;
+	pb->ch1_cmd = 0;
+	pb->ch2_cmd = 0;
+	pb->mask = 0;
+	pb->priv_space = 0;
+	pb->offset = 0;
+	pb->user = 0;
+	pb->overlay = 0;
+	pb->suspendq = NULL;
+	pb->cmd_buff_inited = 0;
+	pb->frame_buffer_phys = 0;
+
+	/* Reset DMA controllers */
+	planb_dbdma_stop(&pb->planb_base->ch2);
+	planb_dbdma_stop(&pb->planb_base->ch1);
+
+	saa_rev =  (saa_status(0, pb) & 0xf0) >> 4;
+	printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev);
+	/* Initialize the SAA registers in memory and on chip */
+	saa_init_regs (pb);
+
+	/* clear interrupt mask */
+	pb->intr_mask = PLANB_CLR_IRQ;
+
+        result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
+        if (result==-EINVAL) {
+                printk(KERN_ERR "PlanB: Bad irq number (%d) or handler\n",
+                       (int)pb->irq);
+                return result;
+        }
+	if (result==-EBUSY) {
+                printk(KERN_ERR "PlanB: I don't know why, but IRQ %d busy\n",
+			(int)pb->irq);
+                return result;
+        }
+        if (result < 0) 
+                return result;
+        
+	/* Now add the template and register the device unit. */
+	memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
+
+	pb->picture.brightness=0x90<<8;
+	pb->picture.contrast = 0x70 << 8;
+	pb->picture.colour = 0x70<<8;
+	pb->picture.hue = 0x8000;
+	pb->picture.whiteness = 0;
+	pb->picture.depth = pb->win.depth;
+
+	pb->frame_stat=NULL;
+	pb->capq=NULL;
+	for(i=0; i<MAX_GBUFFERS; i++) {
+		pb->gbuffer[i]=NULL;
+		pb->gwidth[i]=0;
+		pb->gheight[i]=0;
+		pb->gfmt[i]=0;
+		pb->cap_cmd[i]=NULL;
+#ifndef PLANB_GSCANLINE
+		pb->l_fr_addr[i]=NULL;
+		pb->lsize[i] = 0;
+		pb->lnum[i] = 0;
+#endif
+	}
+	pb->fbuffer=NULL;
+	pb->grabbing=0;
+
+	/* clear interrupts */
+	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+	/* set interrupt mask */
+	pb->intr_mask = PLANB_FRM_IRQ;
+
+	if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ *	Scan for a PlanB controller, request the irq and map the io memory 
+ */
+
+static int find_planb(void)
+{
+	struct planb		*pb;
+	struct device_node	*planb_devices;
+	unsigned char		dev_fn, confreg, bus;
+	unsigned int		old_base, new_base;
+	unsigned int		irq;
+
+	if (_machine != _MACH_Pmac)
+		return 0;
+
+	planb_devices = find_devices("planb");
+	if (planb_devices == 0) {
+		planb_num=0;
+		printk(KERN_WARNING "PlanB: no device found!\n");
+		return planb_num;
+	}
+
+	if (planb_devices->next != NULL)
+		printk(KERN_ERR "Warning: only using first PlanB device!\n");
+	pb = &planbs[0];
+	planb_num = 1;
+
+        if (planb_devices->n_addrs != 1) {
+                printk (KERN_WARNING "PlanB: expecting 1 address for planb "
+                	"(got %d)", planb_devices->n_addrs);
+		return 0;
+	}
+
+	if (planb_devices->n_intrs == 0) {
+		printk(KERN_WARNING "PlanB: no intrs for device %s\n",
+		       planb_devices->full_name);
+		return 0;
+	} else {
+		irq = planb_devices->intrs[0].line;
+	}
+
+	/* Initialize PlanB's PCI registers */
+
+	/* There is a bug with the way OF assigns addresses
+	   to the devices behind the chaos bridge.
+	   control needs only 0x1000 of space, but decodes only
+	   the upper 16 bits. It therefore occupies a full 64K.
+	   OF assigns the planb controller memory within this space;
+	   so we need to change that here in order to access planb. */
+
+	/* We remap to 0xf1000000 in hope that nobody uses it ! */
+
+	bus = (planb_devices->addrs[0].space >> 16) & 0xff;
+	dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
+	confreg = planb_devices->addrs[0].space & 0xff;
+	old_base = planb_devices->addrs[0].address;
+	new_base = 0xf1000000;
+
+	DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
+		"membase 0x%x (base reg. 0x%x)\n",
+		bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
+
+	/* Enable response in memory space, bus mastering,
+	   use memory write and invalidate */
+	pcibios_write_config_word (bus, dev_fn, PCI_COMMAND,
+		PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_COMMAND_INVALIDATE);
+	/* Set PCI Cache line size & latency timer */
+	pcibios_write_config_byte (bus, dev_fn, PCI_CACHE_LINE_SIZE, 0x8);
+	pcibios_write_config_byte (bus, dev_fn, PCI_LATENCY_TIMER, 0x40);
+
+	/* Set the new base address */
+	pcibios_write_config_dword (bus, dev_fn, confreg, new_base);
+
+	planb_regs = (volatile struct planb_registers *)
+						ioremap (new_base, 0x400);
+	pb->planb_base = planb_regs;
+	pb->planb_base_phys = (struct planb_registers *)new_base;
+	pb->irq	= irq;
+	
+	return planb_num;
+}
+
+static void release_planb(void)
+{
+	int i;
+	struct planb *pb;
+
+	for (i=0;i<planb_num; i++) 
+	{
+		pb=&planbs[i];
+
+		/* stop and flash DMAs unconditionally */
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		planb_dbdma_stop(&pb->planb_base->ch1);
+
+		/* clear and free interrupts */
+		pb->intr_mask = PLANB_CLR_IRQ;
+		out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+		free_irq(pb->irq, pb);
+
+		/* make sure all allocated memory are freed */
+		planb_prepare_close(pb);
+
+		printk(KERN_INFO "PlanB: unregistering with v4l\n");
+		video_unregister_device(&pb->video_dev);
+
+		/* note that iounmap() does nothing on the PPC right now */
+		iounmap ((void *)pb->planb_base);
+	}
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+#else
+__initfunc(int init_planbs(struct video_init *unused))
+{
+#endif
+	int i;
+  
+	if (find_planb()<=0)
+		return -EIO;
+
+	for (i=0; i<planb_num; i++) {
+		if (init_planb(&planbs[i])<0) {
+			printk(KERN_ERR "PlanB: error registering device %d"
+							" with v4l\n", i);
+			release_planb();
+			return -EIO;
+		} 
+		printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
+	}  
+	return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	release_planb();
+}
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/char/planb.h linux/drivers/char/planb.h
--- v2.2.7/linux/drivers/char/planb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/planb.h	Fri May  7 11:05:30 1999
@@ -0,0 +1,229 @@
+/* 
+    planb - PlanB frame grabber driver
+
+    PlanB is used in the 7x00/8x00 series of PowerMacintosh
+    Computers as video input DMA controller.
+
+    Copyright (C) 1998 Michel Lanners (ml...@cpu.lu)
+
+    Based largely on the bttv driver by Ralph Metzler (rj...@thp.uni-koeln.de)
+
+    Additional debugging and coding by Takashi Oe (t...@unlinfo.unl.edu)
+
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* $Id: planb.h,v 1.13 1999/05/03 19:28:56 mlan Exp $ */
+
+#ifndef _PLANB_H_
+#define _PLANB_H_
+
+#ifdef __KERNEL__
+#include <asm/dbdma.h>
+#include "saa7196.h"
+#endif /* __KERNEL__ */
+
+#define PLANB_DEVICE_NAME	"Apple PlanB Video-In"
+#define PLANB_REV		"1.0"
+
+#ifdef __KERNEL__
+//#define PLANB_GSCANLINE	/* use this if apps have the notion of */
+				/* grab buffer scanline */
+/* This should be safe for both PAL and NTSC */
+#define PLANB_MAXPIXELS 768
+#define PLANB_MAXLINES 576
+#define PLANB_NTSC_MAXLINES 480
+
+/* Uncomment your preferred norm ;-) */
+#define PLANB_DEF_NORM VIDEO_MODE_PAL
+//#define PLANB_DEF_NORM VIDEO_MODE_NTSC
+//#define PLANB_DEF_NORM VIDEO_MODE_SECAM
+
+/* fields settings */
+#define PLANB_GRAY	0x1	/*  8-bit mono? */
+#define PLANB_COLOUR15	0x2	/* 16-bit mode */
+#define PLANB_COLOUR32	0x4	/* 32-bit mode */
+#define PLANB_CLIPMASK	0x8	/* hardware clipmasking */
+
+/* misc. flags for PlanB DMA operation */
+#define	CH_SYNC		0x1	/* synchronize channels (set by ch1;
+				   cleared by ch2) */
+#define FIELD_SYNC	0x2     /* used for the start of each field
+				   (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */
+#define EVEN_FIELD	0x0	/* even field is detected if unset */
+#define DMA_ABORT	0x2	/* error or just out of sync if set */
+#define ODD_FIELD	0x4	/* odd field is detected if set */
+
+/* for capture operations */
+#define MAX_GBUFFERS	2
+#ifdef PLANB_GSCANLINE
+#define PLANB_MAX_FBUF	0x240000	/* 576 * 1024 * 4 */
+#define TAB_FACTOR	(1)
+#else
+#define PLANB_MAX_FBUF	0x1b0000	/* 576 * 768 * 4 */
+#define TAB_FACTOR	(2)
+#endif
+#endif /* __KERNEL__ */
+
+struct planb_saa_regs {
+	unsigned char addr;
+	unsigned char val;
+};
+
+struct planb_stat_regs {
+	unsigned int ch1_stat;
+	unsigned int ch2_stat;
+	unsigned char saa_stat0;
+	unsigned char saa_stat1;
+};
+
+struct planb_any_regs {
+	unsigned int offset;
+	unsigned int bytes;
+	unsigned char data[128];
+};
+
+/* planb private ioctls */
+#define PLANBIOCGSAAREGS	_IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs)	/* Read a saa7196 reg value */
+#define PLANBIOCSSAAREGS	_IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs)	/* Set a saa7196 reg value */
+#define PLANBIOCGSTAT		_IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs)	/* Read planb status */
+#define PLANB_TV_MODE		1
+#define PLANB_VTR_MODE		2
+#define PLANBIOCGMODE		_IOR('v', BASE_VIDIOCPRIVATE + 3, int)	/* Get TV/VTR mode */
+#define PLANBIOCSMODE		_IOW('v', BASE_VIDIOCPRIVATE + 4, int)	/* Set TV/VTR mode */
+
+#ifdef PLANB_GSCANLINE
+#define PLANBG_GRAB_BPL		_IOR('v', BASE_VIDIOCPRIVATE + 5, int)	/* # of bytes per scanline in grab buffer */
+#endif
+
+/* call wake_up_interruptible() with appropriate actions */
+#define PLANB_INTR_DEBUG	_IOW('v', BASE_VIDIOCPRIVATE + 20, int)
+/* investigate which reg does what */
+#define PLANB_INV_REGS		_IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs)
+
+#ifdef __KERNEL__
+
+/* Potentially useful macros */
+#define PLANB_SET(x)	((x) << 16 | (x))
+#define PLANB_CLR(x)	((x) << 16)
+
+/* This represents the physical register layout */
+struct planb_registers {
+	volatile struct dbdma_regs	ch1;		/* 0x00: video in */
+	volatile unsigned int		even;		/* 0x40: even field setting */
+	volatile unsigned int		odd;		/* 0x44; odd field setting */
+	unsigned int			pad1[14];	/* empty? */
+	volatile struct dbdma_regs	ch2;		/* 0x80: clipmask out */
+	unsigned int			pad2[16];	/* 0xc0: empty? */
+	volatile unsigned int		reg3;		/* 0x100: ???? */
+	volatile unsigned int		intr_stat;	/* 0x104: irq status */
+#define PLANB_CLR_IRQ		0x00		/* clear Plan B interrupt */
+#define PLANB_GEN_IRQ		0x01		/* assert Plan B interrupt */
+#define PLANB_FRM_IRQ		0x02		/* end of frame */
+#define PLANB_IRQ_CMD_MASK	0x00000003U	/* reserve 2 lsbs for command */
+	unsigned int			pad3[1];	/* empty? */
+	volatile unsigned int		reg5;		/* 0x10c: ??? */
+	unsigned int			pad4[60];	/* empty? */
+	volatile unsigned char		saa_addr;	/* 0x200: SAA subadr */
+	char				pad5[3];
+	volatile unsigned char		saa_regval;	/* SAA7196 write reg. val */
+	char				pad6[3];
+	volatile unsigned char		saa_status;	/* SAA7196 status byte */
+	/* There is more unused stuff here */
+};
+
+struct planb_window {
+	int	x, y;
+	ushort	width, height;
+	ushort	bpp, bpl, depth, pad;
+	ushort	swidth, sheight;
+	int	norm;
+	int	interlace;
+	u32	color_fmt;
+	int	chromakey;
+	int	mode;		/* used to switch between TV/VTR modes */
+};
+
+struct planb_suspend {
+	int overlay;
+	int frame;
+	struct dbdma_cmd cmd;
+};
+
+struct planb {
+	struct	video_device video_dev;
+	struct	video_picture picture;		/* Current picture params */
+	struct	video_audio audio_dev;		/* Current audio params */
+  
+	volatile struct planb_registers *planb_base;	/* virt base of planb */
+	struct planb_registers *planb_base_phys;	/* phys base of planb */
+	void	*priv_space;			/* Org. alloc. mem for kfree */
+	int	user;
+	unsigned int tab_size;
+	int     maxlines;
+	int lock;
+	struct wait_queue *lockq;
+	unsigned int	irq;			/* interrupt number */
+	volatile unsigned int intr_mask;
+
+	int	overlay;			/* overlay running? */
+	struct	planb_window win;
+	unsigned long frame_buffer_phys;	/* We need phys for DMA */
+	int	offset;				/* offset of pixel 1 */
+	volatile struct dbdma_cmd *ch1_cmd;	/* Video In DMA cmd buffer */
+	volatile struct dbdma_cmd *ch2_cmd;	/* Clip Out DMA cmd buffer */
+	volatile struct dbdma_cmd *overlay_last1;
+	volatile struct dbdma_cmd *overlay_last2;
+	unsigned long ch1_cmd_phys;
+	volatile unsigned char *mask;		/* Clipmask buffer */
+	int suspend;
+	struct wait_queue *suspendq;
+	struct planb_suspend suspended;
+	int	cmd_buff_inited;		/* cmd buffer inited? */
+
+	int grabbing;
+	unsigned int gcount;
+	struct wait_queue *capq;
+	int last_fr;
+	int prev_last_fr;
+        unsigned char *fbuffer;
+	unsigned char *gbuffer[MAX_GBUFFERS];
+	volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS];
+	volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS];
+	volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS];
+	int need_pre_capture[MAX_GBUFFERS];
+#define PLANB_DUMMY 40	/* # of command buf's allocated for pre-capture seq. */
+	int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS];
+	unsigned int gfmt[MAX_GBUFFERS];
+	int gnorm_switch[MAX_GBUFFERS];
+        volatile unsigned int *frame_stat;
+#define GBUFFER_UNUSED       0x00U
+#define GBUFFER_GRABBING     0x01U
+#define GBUFFER_DONE         0x02U
+#ifdef PLANB_GSCANLINE
+	int gbytes_per_line;
+#else
+#define MAX_LNUM 431	/* change this if PLANB_MAXLINES or */
+			/* PLANB_MAXPIXELS changes */
+	unsigned char *l_fr_addr[MAX_GBUFFERS];
+	unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM];
+	int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS];
+#endif
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _PLANB_H_ */
diff -u --recursive --new-file v2.2.7/linux/drivers/char/radio-cadet.c linux/drivers/char/radio-cadet.c
--- v2.2.7/linux/drivers/char/radio-cadet.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/radio-cadet.c	Mon May 10 13:00:10 1999
@@ -1,7 +1,7 @@
X /* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card 
X  *
X  * by Fred Gleason <fr...@wava.com>
- * Version 0.1.2
+ * Version 0.3.1
X  *
X  * (Loosely) based on code for the Aztech radio card by
X  *
@@ -22,42 +22,110 @@
X #include <asm/uaccess.h>	/* copy to/from user		*/
X #include <linux/videodev.h>	/* kernel radio structs		*/
X #include <linux/config.h>	/* CONFIG_RADIO_CADET_PORT 	*/
+#include <linux/param.h>
X 
X #ifndef CONFIG_RADIO_CADET_PORT
X #define CONFIG_RADIO_CADET_PORT 0x330
X #endif
+#define RDS_BUFFER 256
X 
X static int io=CONFIG_RADIO_CADET_PORT; 
X static int users=0;
X static int curtuner=0;
+static int tunestat=0;
+static int sigstrength=0;
+struct wait_queue *tunerq,*rdsq,*readq;
+struct timer_list tunertimer,rdstimer,readtimer;
+static __u8 rdsin=0,rdsout=0,rdsstat=0;
+static unsigned char rdsbuf[RDS_BUFFER];
+static int cadet_lock=0;
+
+/*
+ * Signal Strength Threshold Values
+ * The V4L API spec does not define any particular unit for the signal 
+ * strength value.  These values are in microvolts of RF at the tuner's input.
+ */
+static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
+
+
+
+void cadet_wake(unsigned long qnum)
+{
+        switch(qnum) {
+	case 0:           /* cadet_setfreq */
+	        wake_up(&tunerq);
+		break;
+	case 1:           /* cadet_getrds */
+	        wake_up(&rdsq);
+		break;
+	}	
+}
+
+
+
+static int cadet_getrds(void)
+{
+        int rdsstat=0;
+
+	cadet_lock++;
+        outb(3,io);                 /* Select Decoder Control/Status */
+	outb(inb(io+1)&0x7f,io+1);  /* Reset RDS detection */
+	cadet_lock--;
+	init_timer(&rdstimer);
+	rdstimer.function=cadet_wake;
+	rdstimer.data=(unsigned long)1;
+	rdstimer.expires=jiffies+(HZ/10);
+	rdsq=NULL;
+	add_timer(&rdstimer);
+	sleep_on(&rdsq);
+	
+	cadet_lock++;
+        outb(3,io);                 /* Select Decoder Control/Status */
+	if((inb(io+1)&0x80)!=0) {
+	        rdsstat|=VIDEO_TUNER_RDS_ON;
+	}
+	if((inb(io+1)&0x10)!=0) {
+	        rdsstat|=VIDEO_TUNER_MBS_ON;
+	}
+	cadet_lock--;
+	return rdsstat;
+}
+
+
+
X 
X static int cadet_getstereo(void)
X {
-  if(curtuner!=0) {          /* Only FM has stereo capability! */
+        if(curtuner!=0) {          /* Only FM has stereo capability! */
X 	        return 0;
X 	}
+        cadet_lock++;
X         outb(7,io);          /* Select tuner control */
X         if((inb(io+1)&0x40)==0) {
+	        cadet_lock--;
X                 return 1;    /* Stereo pilot detected */
X         }
X         else {
+	        cadet_lock--;
X                 return 0;    /* Mono */
X         }
X }
X 
X 
-static unsigned cadet_getfreq(void)
+
+static unsigned cadet_gettune(void)
X {
X         int curvol,i;
-        unsigned freq=0,test,fifo=0;
-  
+	unsigned fifo=0;
X 
X         /*
X          * Prepare for read
X          */
+	cadet_lock++;
X         outb(7,io);       /* Select tuner control */
X         curvol=inb(io+1); /* Save current volume/mute setting */
X         outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
+	tunestat=0xffff;
X 
X         /*
X          * Read the shift register
@@ -66,6 +134,7 @@
X                 fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
X                 if(i<24) {
X                         outb(0x01,io+1);
+			tunestat&=inb(io+1);
X                         outb(0x00,io+1);
X                 }
X         }
@@ -74,6 +143,22 @@
X          * Restore volume/mute setting
X          */
X         outb(curvol,io+1);
+	cadet_lock--;
+	
+	return fifo;
+}
+
+
+
+static unsigned cadet_getfreq(void)
+{
+        int i;
+        unsigned freq=0,test,fifo=0;
+
+	/*
+	 * Read current tuning
+	 */
+	fifo=cadet_gettune();
X 
X         /*
X          * Convert to actual frequency
@@ -98,10 +183,40 @@
X }
X 
X 
+
+static void cadet_settune(unsigned fifo)
+{
+        int i;
+	unsigned test;  
+
+	cadet_lock++;
+	outb(7,io);                /* Select tuner control */
+	/*
+	 * Write the shift register
+	 */
+	test=0;
+	test=(fifo>>23)&0x02;      /* Align data for SDO */
+	test|=0x1c;                /* SDM=1, SWE=1, SEN=1, SCK=0 */
+	outb(7,io);                /* Select tuner control */
+	outb(test,io+1);           /* Initialize for write */
+	for(i=0;i<25;i++) {
+   	        test|=0x01;              /* Toggle SCK High */
+		outb(test,io+1);
+		test&=0xfe;              /* Toggle SCK Low */
+		outb(test,io+1);
+		fifo=fifo<<1;            /* Prepare the next bit */
+		test=0x1c|((fifo>>23)&0x02);
+		outb(test,io+1);
+	}
+	cadet_lock--;
+}
+
+
+
X static void cadet_setfreq(unsigned freq)
X {
X         unsigned fifo;
-        int i,test;
+        int i,j,test;
X         int curvol;
X 
X         /* 
@@ -129,39 +244,47 @@
X         /*
X          * Save current volume/mute setting
X          */
+	cadet_lock++;
+	outb(7,io);                /* Select tuner control */
X         curvol=inb(io+1); 
X 
-        /*
-         * Write the shift register
-         */
-        test=0;
-        test=(fifo>>23)&0x02;      /* Align data for SDO */
-        test|=0x1c;                /* SDM=1, SWE=1, SEN=1, SCK=0 */
-        outb(7,io);                /* Select tuner control */
-        outb(test,io+1);           /* Initialize for write */
-        for(i=0;i<25;i++) {
-                test|=0x01;              /* Toggle SCK High */
-                outb(test,io+1);
-                test&=0xfe;              /* Toggle SCK Low */
-                outb(test,io+1);
-                fifo=fifo<<1;            /* Prepare the next bit */
-                test=0x1c|((fifo>>23)&0x02);
-                outb(test,io+1);
-        }
-        /*
-         * Restore volume/mute setting
-         */
-        outb(curvol,io+1);
+	/*
+	 * Tune the card
+	 */
+	for(j=3;j>-1;j--) {
+	        cadet_settune(fifo|(j<<16));
+		outb(7,io);         /* Select tuner control */
+		outb(curvol,io+1);
+		cadet_lock--;
+		init_timer(&tunertimer);
+		tunertimer.function=cadet_wake;
+		tunertimer.data=(unsigned long)0;
+		tunertimer.expires=jiffies+(HZ/10);
+		tunerq=NULL;
+		add_timer(&tunertimer);
+		sleep_on(&tunerq);
+		cadet_gettune();
+		if((tunestat&0x40)==0) {   /* Tuned */
+		        sigstrength=sigtable[curtuner][j];
+			return;
+		}
+		cadet_lock++;
+	}
+	cadet_lock--;
+	sigstrength=0;
X }
X 
X 
X static int cadet_getvol(void)
X {
+        cadet_lock++;
X         outb(7,io);                /* Select tuner control */
X         if((inb(io+1)&0x20)!=0) {
+	        cadet_lock--;
X                 return 0xffff;
X         }
X         else {
+	        cadet_lock--;
X                 return 0;
X         }
X }
@@ -169,6 +292,7 @@
X 
X static void cadet_setvol(int vol)
X {
+        cadet_lock++;
X         outb(7,io);                /* Select tuner control */
X         if(vol>0) {
X                 outb(0x20,io+1);
@@ -176,9 +300,88 @@
X         else {
X                 outb(0x00,io+1);
X         }
+	cadet_lock--;
X }  
X 
X 
+
+void cadet_handler(unsigned long data)
+{
+	/*
+	 * Service the RDS fifo
+	 */
+        if(cadet_lock==0) {
+	        outb(0x3,io);       /* Select RDS Decoder Control */
+		if((inb(io+1)&0x20)!=0) {
+		        printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+		}
+		outb(0x80,io);      /* Select RDS fifo */
+		while((inb(io)&0x80)!=0) {
+		        rdsbuf[rdsin++]=inb(io+1);
+			if(rdsin==rdsout) {
+			        printk(KERN_CRIT "cadet: RDS buffer overflow\n");
+			}
+		}
+	}
+
+	/*
+	 * Service pending read
+	 */
+	if((rdsin!=rdsout)&&(readq!=NULL)) {
+	        wake_up_interruptible(&readq);
+	}
+
+	/* 
+	 * Clean up and exit
+	 */
+	init_timer(&readtimer);
+	readtimer.function=cadet_handler;
+	readtimer.data=(unsigned long)0;
+	readtimer.expires=jiffies+(HZ/20);
+	add_timer(&readtimer);
+}
+
+
+
+static long cadet_read(struct video_device *v,char *buf,unsigned long count,
+		       int nonblock)
+{
+        int i=0,c;
+	unsigned char readbuf[RDS_BUFFER];
+
+        if(rdsstat==0) {
+	        cadet_lock++;
+	        rdsstat=1;
+		outb(0x80,io);        /* Select RDS fifo */
+		c=3*(inb(io)&0x03);
+		for(i=0;i<c;i++) {    /* Flush the fifo */
+		        inb(io+1);
+		}
+		cadet_lock--;
+		init_timer(&readtimer);
+		readtimer.function=cadet_handler;
+		readtimer.data=(unsigned long)0;
+		readtimer.expires=jiffies+(HZ/20);
+		add_timer(&readtimer);
+	}
+	if(rdsin==rdsout) {
+  	        if(nonblock) {
+		        return -EWOULDBLOCK;
+		}
+	        interruptible_sleep_on(&readq);
+       		readq=NULL;
+	}		
+	while((i<count)&&(rdsin!=rdsout)) {
+	        readbuf[i++]=rdsbuf[rdsout++];
+	}
+	if(copy_to_user(buf,readbuf,i)) {
+	        return -EFAULT;
+	}
+	return i;
+}
+
+
+
X static int cadet_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
X {
X         unsigned freq;
@@ -217,10 +420,11 @@
X 			        v.flags=0;
X 			        v.mode=0;
X 			        v.mode|=VIDEO_MODE_AUTO;
-			        v.signal=0xFFFF;
+			        v.signal=sigstrength;
X 			        if(cadet_getstereo()==1) {
X 				        v.flags|=VIDEO_TUNER_STEREO_ON;
X 			        }
+				v.flags|=cadet_getrds();
X 			        if(copy_to_user(arg,&v, sizeof(v))) {
X 				        return -EFAULT;
X 			        }
@@ -233,7 +437,7 @@
X 			        v.flags|=VIDEO_TUNER_LOW;
X 			        v.mode=0;
X 			        v.mode|=VIDEO_MODE_AUTO;
-			        v.signal=0xFFFF;
+			        v.signal=sigstrength;
X 			        if(copy_to_user(arg,&v, sizeof(v))) {
X 				        return -EFAULT;
X 			        }
@@ -313,11 +517,16 @@
X 		return -EBUSY;
X 	users++;
X 	MOD_INC_USE_COUNT;
+	readq=NULL;
X 	return 0;
X }
X 
X static void cadet_close(struct video_device *dev)
X {
+        if(rdsstat==1) {
+                del_timer(&readtimer);
+		rdsstat=0;
+	}
X 	users--;
X 	MOD_DEC_USE_COUNT;
X }
@@ -330,7 +539,7 @@
X 	VID_HARDWARE_CADET,
X 	cadet_open,
X 	cadet_close,
-	NULL,	/* Can't read  (no capture ability) */
+	cadet_read,
X 	NULL,	/* Can't write */
X 	NULL,	/* No poll */
X 	cadet_ioctl,
@@ -354,6 +563,7 @@
X }
X 
X 
+#ifndef MODULE
X static int cadet_probe(void)
X {
X         static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
@@ -371,6 +581,7 @@
X 	}
X 	return -1;
X }
+#endif
X 
X 
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/char/radio-typhoon.c linux/drivers/char/radio-typhoon.c
--- v2.2.7/linux/drivers/char/radio-typhoon.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/radio-typhoon.c	Mon May 10 13:00:10 1999
@@ -48,6 +48,10 @@
X #define CONFIG_RADIO_TYPHOON_MUTEFREQ 0
X #endif
X 
+#ifndef CONFIG_PROC_FS
+#undef CONFIG_RADIO_TYPHOON_PROC_FS
+#endif
+
X struct typhoon_device {
X 	int users;
X 	int iobase;
diff -u --recursive --new-file v2.2.7/linux/drivers/char/radio-zoltrix.c linux/drivers/char/radio-zoltrix.c
--- v2.2.7/linux/drivers/char/radio-zoltrix.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/radio-zoltrix.c	Mon May 10 13:00:10 1999
@@ -5,15 +5,16 @@
X  *  Due to the inconsistancy in reading from the signal flags
X  *  it is difficult to get an accurate tuned signal.
X  *
- *  There seems to be a problem with the volume setting that I must still
- *  figure out. 
- *  It seems that the card has is not linear to 0 volume. It cuts off
- *  at a low frequency, and it is not possible (at least I have not found)
+ *  It seems that the card is not linear to 0 volume. It cuts off
+ *  at a low volume, and it is not possible (at least I have not found)
X  *  to get fine volume control over the low volume range.
X  *
X  *  Some code derived from code by Romolo Manfredini
X  *				   rom...@bicnet.it
X  *
+ * 1999-05-06 - (C. van Schaik)
+ *	      - Make signal strength and stereo scans
+ *	        kinder to cpu while in delay
X  * 1999-01-05 - (C. van Schaik)
X  *	      - Changed tuning to 1/160Mhz accuracy
X  *	      - Added stereo support
@@ -51,18 +52,10 @@
X 
X /* local things */
X 
-static void sleep_delay(long n)
+static void sleep_delay(void)
X {
-	/* Sleep nicely for 'n' uS */
-	int d = n / (1000000 / HZ);
-	if (!d)
-		udelay(n);
-	else {
-		/* Yield CPU time */
-		unsigned long x = jiffies;
-		while ((jiffies - x) <= d)
-			schedule();
-	}
+	/* Sleep nicely for +/- 10 mS */
+	schedule();
X }
X 
X static int zol_setvol(struct zol_device *dev, int vol)
@@ -79,7 +72,7 @@
X 	}
X 
X 	outb(dev->curvol-1, io);
-	sleep_delay(10000);
+	sleep_delay();
X 	inb(io + 2);
X 
X 	return 0;
@@ -125,18 +118,18 @@
X 	while (i--) {
X 		if ((bitmask & 0x8000000000000000ull) != 0) {
X 			outb(0x80, io);
-			sleep_delay(50);
+			udelay(50);
X 			outb(0x00, io);
-			sleep_delay(50);
+			udelay(50);
X 			outb(0x80, io);
-			sleep_delay(50);
+			udelay(50);
X 		} else {
X 			outb(0xc0, io);
-			sleep_delay(50);
+			udelay(50);
X 			outb(0x40, io);
-			sleep_delay(50);
+			udelay(50);
X 			outb(0xc0, io);
-			sleep_delay(50);
+			udelay(50);
X 		}
X 		bitmask *= 2;
X 	}
@@ -144,16 +137,16 @@
X 	outb(0x80, io);
X 	outb(0xc0, io);
X 	outb(0x40, io);
-	sleep_delay(1000);
+	udelay(1000);
X 	inb(io+2);
X 
-        sleep_delay(1000);
+        udelay(1000);
X 	if (dev->muted)
X 	{
X 		outb(0, io);
X 		outb(0, io);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 14'
echo 'File patch-2.2.8 is continued in part 15'
echo 15 > _shar_seq_.tmp
#!/bin/sh
# this is part 15 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 15; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 		inb(io + 3);
-		sleep_delay(1000);
+		udelay(1000);
X 	} else
X         zol_setvol(dev, dev->curvol);
X 	return 0;
@@ -167,10 +160,11 @@
X 
X 	outb(0x00, io);         /* This stuff I found to do nothing */
X 	outb(dev->curvol, io);
-	sleep_delay(20000);
+	sleep_delay();
+	sleep_delay();
X 
X 	a = inb(io);
-	sleep_delay(1000);
+	sleep_delay();
X 	b = inb(io);
X 
X 	if (a != b)
@@ -188,10 +182,11 @@
X 
X 	outb(0x00, io);
X 	outb(dev->curvol, io);
-	sleep_delay(20000);
+	sleep_delay();
+	sleep_delay();
X 
X 	x1 = inb(io);
-	sleep_delay(1000);
+	sleep_delay();
X 	x2 = inb(io);
X 
X 	if ((x1 == x2) && (x1 == 0xcf))
@@ -362,7 +357,8 @@
X 
X 	outb(0, io);
X 	outb(0, io);
-	sleep_delay(20000);
+	sleep_delay();
+	sleep_delay();
X 	inb(io + 3);
X 
X 	zoltrix_unit.curvol = 0;
diff -u --recursive --new-file v2.2.7/linux/drivers/char/saa7196.h linux/drivers/char/saa7196.h
--- v2.2.7/linux/drivers/char/saa7196.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/saa7196.h	Fri May  7 11:05:30 1999
@@ -0,0 +1,117 @@
+/*
+    Definitions for the Philips SAA7196 digital video decoder,
+    scaler, and clock generator circuit (DESCpro), as used in
+    the PlanB video input of the Powermac 7x00/8x00 series.
+  
+    Copyright (C) 1998 Michel Lanners (ml...@cpu.lu)
+
+    The register defines are shamelessly copied from the meteor
+    driver out of NetBSD (with permission),
+    and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe
+    (Thanks !)
+  
+    Additional debugging and coding by Takashi Oe (t...@unlinfo.unl.edu)
+
+    The default values used for PlanB are my mistakes.
+*/
+
+/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */
+
+#ifndef _SAA7196_H_
+#define _SAA7196_H_
+
+#define SAA7196_NUMREGS	0x31	/* Number of registers (used)*/
+#define NUM_SUPPORTED_NORM 3	/* Number of supported norms by PlanB */
+
+/* Decoder part: */
+#define SAA7196_IDEL    0x00    /* Increment delay */
+#define SAA7196_HSB5    0x01    /* H-sync begin; 50 hz */
+#define SAA7196_HSS5    0x02    /* H-sync stop; 50 hz */
+#define SAA7196_HCB5    0x03    /* H-clamp begin; 50 hz */
+#define SAA7196_HCS5    0x04    /* H-clamp stop; 50 hz */
+#define SAA7196_HSP5    0x05    /* H-sync after PHI1; 50 hz */
+#define SAA7196_LUMC    0x06    /* Luminance control */
+#define SAA7196_HUEC    0x07    /* Hue control */
+#define SAA7196_CKTQ    0x08    /* Colour Killer Threshold QAM (PAL, NTSC) */
+#define SAA7196_CKTS    0x09    /* Colour Killer Threshold SECAM */
+#define SAA7196_PALS    0x0a    /* PAL switch sensitivity */
+#define SAA7196_SECAMS  0x0b    /* SECAM switch sensitivity */
+#define SAA7196_CGAINC  0x0c    /* Chroma gain control */
+#define SAA7196_STDC    0x0d    /* Standard/Mode control */
+#define SAA7196_IOCC    0x0e    /* I/O and Clock Control */
+#define SAA7196_CTRL1   0x0f    /* Control #1 */
+#define SAA7196_CTRL2   0x10    /* Control #2 */
+#define SAA7196_CGAINR  0x11    /* Chroma Gain Reference */
+#define SAA7196_CSAT    0x12    /* Chroma Saturation */
+#define SAA7196_CONT    0x13    /* Luminance Contrast */
+#define SAA7196_HSB6    0x14    /* H-sync begin; 60 hz */
+#define SAA7196_HSS6    0x15    /* H-sync stop; 60 hz */
+#define SAA7196_HCB6    0x16    /* H-clamp begin; 60 hz */
+#define SAA7196_HCS6    0x17    /* H-clamp stop; 60 hz */
+#define SAA7196_HSP6    0x18    /* H-sync after PHI1; 60 hz */
+#define SAA7196_BRIG    0x19    /* Luminance Brightness */
+
+/* Scaler part: */
+#define SAA7196_FMTS    0x20    /* Formats and sequence */
+#define SAA7196_OUTPIX  0x21    /* Output data pixel/line */
+#define SAA7196_INPIX   0x22    /* Input data pixel/line */
+#define SAA7196_HWS     0x23    /* Horiz. window start */
+#define SAA7196_HFILT   0x24    /* Horiz. filter */
+#define SAA7196_OUTLINE 0x25    /* Output data lines/field */
+#define SAA7196_INLINE  0x26    /* Input data lines/field */
+#define SAA7196_VWS     0x27    /* Vertical window start */
+#define SAA7196_VYP     0x28    /* AFS/vertical Y processing */
+#define SAA7196_VBS     0x29    /* Vertical Bypass start */
+#define SAA7196_VBCNT   0x2a    /* Vertical Bypass count */
+#define SAA7196_VBP     0x2b    /* veritcal Bypass Polarity */
+#define SAA7196_VLOW    0x2c    /* Colour-keying lower V limit */
+#define SAA7196_VHIGH   0x2d    /* Colour-keying upper V limit */
+#define SAA7196_ULOW    0x2e    /* Colour-keying lower U limit */
+#define SAA7196_UHIGH   0x2f    /* Colour-keying upper U limit */
+#define SAA7196_DPATH   0x30    /* Data path setting  */
+
+/* Initialization default values: */
+
+unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = {
+
+/* PAL, 768x576 (no scaling), composite video-in */
+/* Decoder: */
+      { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff,
+	0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98,
+	0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2,
+	0xe9, 0xa2,
+/* Padding */
+		    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/* Scaler: */
+	0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12,
+	0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
+	0x87 },
+
+/* NTSC, 640x480? (no scaling), composite video-in */
+/* Decoder: */
+      { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00,
+	0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98,
+	0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2,
+	0xe9, 0x98,
+/* Padding */
+		    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/* Scaler: */
+	0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d,
+	0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
+	0x87 },
+
+/* SECAM, 768x576 (no scaling), composite video-in */
+/* Decoder: */
+      { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff,
+	0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98,
+	0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2,
+	0xe9, 0xa2,
+/* Padding */
+		    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/* Scaler: */
+	0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12,
+	0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
+	0x87 }
+	};
+
+#endif /* _SAA7196_H_ */
diff -u --recursive --new-file v2.2.7/linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- v2.2.7/linux/drivers/char/specialix.c	Thu Dec 31 10:29:00 1998
+++ linux/drivers/char/specialix.c	Sun May  2 09:51:09 1999
@@ -2355,6 +2355,9 @@
X 
X int irq [SX_NBOARD] = {0,};
X 
+MODULE_PARM(iobase,"1-" __MODULE_STRING(SX_NBOARD) "i");
+MODULE_PARM(irq,"1-" __MODULE_STRING(SX_NBOARD) "i");
+
X /*
X  * You can setup up to 4 boards.
X  * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
diff -u --recursive --new-file v2.2.7/linux/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h
--- v2.2.7/linux/drivers/isdn/act2000/act2000.h	Wed Apr  1 20:11:49 1998
+++ linux/drivers/isdn/act2000/act2000.h	Mon May 10 13:00:10 1999
@@ -213,7 +213,7 @@
X         char regname[35];                /* Name used for request_region     */
X } act2000_card;
X 
-extern act2000_card *cards;
+extern act2000_card *actcards;
X 
X extern __inline__ void act2000_schedule_tx(act2000_card *card)
X {
diff -u --recursive --new-file v2.2.7/linux/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c
--- v2.2.7/linux/drivers/isdn/act2000/module.c	Wed Apr  1 20:11:49 1998
+++ linux/drivers/isdn/act2000/module.c	Mon May 10 13:00:10 1999
@@ -57,7 +57,7 @@
X };
X #define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short))
X 
-act2000_card *cards = (act2000_card *) NULL;
+act2000_card *actcards = (act2000_card *) NULL;
X 
X /* Parameters to be set by insmod */
X static int   act_bus  =  0;
@@ -589,7 +589,7 @@
X static inline act2000_card *
X act2000_findcard(int driverid)
X {
-        act2000_card *p = cards;
+        act2000_card *p = actcards;
X 
X         while (p) {
X                 if (p->myid == driverid)
@@ -714,8 +714,8 @@
X         card->bus = bus;
X         card->port = port;
X         card->irq = irq;
-        card->next = cards;
-        cards = card;
+        card->next = actcards;
+        actcards = card;
X }
X 
X /*
@@ -805,9 +805,9 @@
X 				       bus);
X 		}
X 	}
-	if (!cards)
+	if (!actcards)
X 		return 1;
-        p = cards;
+        p = actcards;
X         while (p) {
X 		initialized = 0;
X 		if (!p->interface.statcallb) {
@@ -870,9 +870,9 @@
X                                 kfree(p);
X                                 p = q->next;
X                         } else {
-                                cards = p->next;
+                                actcards = p->next;
X                                 kfree(p);
-                                p = cards;
+                                p = actcards;
X                         }
X 			failed++;
X                 }
@@ -890,9 +890,9 @@
X act2000_init(void)
X {
X         printk(KERN_INFO "%s\n", DRIVERNAME);
-        if (!cards)
+        if (!actcards)
X 		act2000_addcard(act_bus, act_port, act_irq, act_id);
-        if (!cards)
+        if (!actcards)
X                 printk(KERN_INFO "act2000: No cards defined yet\n");
X         /* No symbols to export, hide all symbols */
X         EXPORT_NO_SYMBOLS;
@@ -903,14 +903,14 @@
X void
X cleanup_module(void)
X {
-        act2000_card *card = cards;
+        act2000_card *card = actcards;
X         act2000_card *last;
X         while (card) {
X                 unregister_card(card);
X 		del_timer(&card->ptimer);
X                 card = card->next;
X         }
-        card = cards;
+        card = actcards;
X         while (card) {
X                 last = card;
X                 card = card->next;
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- v2.2.7/linux/drivers/macintosh/Makefile	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/Makefile	Thu Apr 29 12:53:48 1999
@@ -16,7 +16,7 @@
X M_OBJS   :=
X 
X ifndef CONFIG_MBX
-L_OBJS   := via-cuda.o nvram.o macio-adb.o via-pmu.o mediabay.o
+L_OBJS   := via-cuda.o macio-adb.o via-pmu.o mediabay.o
X LX_OBJS  := adb.o
X endif
X 
@@ -25,6 +25,14 @@
X else
X   ifeq ($(CONFIG_MAC_SERIAL),m)
X     M_OBJS += macserial.o
+  endif
+endif
+
+ifeq ($(CONFIG_NVRAM),y)
+  L_OBJS += nvram.o
+else
+  ifeq ($(CONFIG_NVRAM),m)
+    M_OBJS += nvram.o
X   endif
X endif
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.2.7/linux/drivers/macintosh/adb.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/macintosh/adb.c	Thu Apr 29 12:53:48 1999
@@ -3,8 +3,19 @@
X  * and the /dev/adb device on macintoshes.
X  *
X  * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Modified to declare controllers as structures, added
+ * client notification of bus reset and handles PowerBook
+ * sleep, by Benjamin Herrenschmidt.
+ *
+ * To do:
+ *
+ * - /proc/adb to list the devices and infos
+ * - more /dev/adb to allow userland to receive the
+ *   flow of auto-polling datas from a given device.
X  */
X 
+#include <linux/config.h>
X #include <linux/types.h>
X #include <linux/errno.h>
X #include <linux/kernel.h>
@@ -21,12 +32,23 @@
X #include <asm/hydra.h>
X #include <asm/init.h>
X 
+EXPORT_SYMBOL(adb_controller);
+EXPORT_SYMBOL(adb_client_list);
X EXPORT_SYMBOL(adb_hardware);
X 
+struct adb_controller *adb_controller = NULL;
+struct notifier_block *adb_client_list = NULL;
X enum adb_hw adb_hardware = ADB_NONE;
-int (*adb_send_request)(struct adb_request *req, int sync);
-int (*adb_autopoll)(int devs);
-int (*adb_reset_bus)(void);
+
+#ifdef CONFIG_PMAC_PBOOK
+static int adb_notify_sleep(struct notifier_block *, unsigned long, void *);
+static struct notifier_block adb_sleep_notifier = {
+	adb_notify_sleep,
+	NULL,
+	0
+};
+#endif
+
X static int adb_scan_bus(void);
X 
X static struct adb_handler {
@@ -35,13 +57,6 @@
X 	int handler_id;
X } adb_handler[16];
X 
-__openfirmware
-
-static int adb_nodev(void)
-{
-	return -1;
-}
-
X #if 0
X static void printADBreply(struct adb_request *req)
X {
@@ -61,8 +76,6 @@
X 	int devmask = 0;
X 	struct adb_request req;
X 	
-	adb_reset_bus();	/* reset ADB bus */
-
X 	/* assumes adb_handler[] is all zeroes at this point */
X 	for (i = 1; i < 16; i++) {
X 		/* see if there is anything at address i */
@@ -147,22 +160,96 @@
X 
X void adb_init(void)
X {
-	adb_send_request = (void *) adb_nodev;
-	adb_autopoll = (void *) adb_nodev;
-	adb_reset_bus = adb_nodev;
X 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
X 		return;
+
X 	via_cuda_init();
X 	via_pmu_init();
X 	macio_adb_init();
-	if (adb_hardware == ADB_NONE)
+	
+	if (adb_controller == NULL)
X 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
-	else {
-		int devs = adb_scan_bus();
-		adb_autopoll(devs);
+	else
+	{
+		adb_hardware = adb_controller->kind;
+#ifdef CONFIG_PMAC_PBOOK
+		notifier_chain_register(&sleep_notifier_list,
+					&adb_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+		adb_reset_bus();
+	}
+}
+
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int
+adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x)
+{
+	int ret;
+	
+	switch (code) {
+		case PBOOK_SLEEP:
+			ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
+			if (ret & NOTIFY_STOP_MASK)
+				return -EBUSY;
+		case PBOOK_WAKE:
+			adb_reset_bus();
+			break;
+	}
+	return NOTIFY_DONE;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+int
+adb_reset_bus(void)
+{
+	int ret, 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)
+		return -EBUSY;
+
+	save_flags(flags);
+	cli();
+	memset(adb_handler, 0, sizeof(adb_handler));
+	restore_flags(flags);
+	
+	if (adb_controller->reset_bus)
+		ret = adb_controller->reset_bus();
+	else
+		ret = 0;
+
+	if (!ret)
+	{
+		devs = adb_scan_bus();
+		if (adb_controller->autopoll)
+			adb_controller->autopoll(devs);
X 	}
+
+	ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+	if (ret & NOTIFY_STOP_MASK)
+		return -EBUSY;
+	
+	return 1;
+}
+
+void
+adb_poll(void)
+{
+	if ((adb_controller == NULL)||(adb_controller->poll == NULL))
+		return;
+	adb_controller->poll();
X }
X 
+
X int
X adb_request(struct adb_request *req, void (*done)(struct adb_request *),
X 	    int flags, int nbytes, ...)
@@ -171,18 +258,25 @@
X 	int i;
X 	struct adb_request sreq;
X 
+	if ((adb_controller == NULL) || (adb_controller->send_request == NULL))
+		return -ENXIO;
+	if (nbytes < 1)
+		return -EINVAL;
+	
X 	if (req == NULL) {
X 		req = &sreq;
X 		flags |= ADBREQ_SYNC;
X 	}
-	req->nbytes = nbytes;
+	req->nbytes = nbytes+1;
X 	req->done = done;
X 	req->reply_expected = flags & ADBREQ_REPLY;
+	req->data[0] = ADB_PACKET;
X 	va_start(list, nbytes);
X 	for (i = 0; i < nbytes; ++i)
-		req->data[i] = va_arg(list, int);
+		req->data[i+1] = va_arg(list, int);
X 	va_end(list);
-	return adb_send_request(req, flags & ADBREQ_SYNC);
+
+	return adb_controller->send_request(req, flags & ADBREQ_SYNC);
X }
X 
X  /* Ultimately this should return the number of devices with
@@ -247,7 +341,7 @@
X 	if (req.reply_len < 2)
X 	    return 0;
X 	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(address, 3), req.reply[1], new_id);	
+	    ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id);	
X 	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
X 	    ADB_READREG(address, 3));
X 	if (req.reply_len < 2)
@@ -318,7 +412,7 @@
X {
X 	struct adbdev_state *state;
X 
-	if (MINOR(inode->i_rdev) > 0 || adb_hardware == ADB_NONE)
+	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
X 		return -ENXIO;
X 	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
X 	if (state == 0)
@@ -420,7 +514,7 @@
X static ssize_t adb_write(struct file *file, const char *buf,
X 			 size_t count, loff_t *ppos)
X {
-	int ret, i;
+	int ret/*, i*/;
X 	struct adbdev_state *state = file->private_data;
X 	struct adb_request *req;
X 
@@ -439,36 +533,26 @@
X 	req->done = adb_write_done;
X 	req->arg = (void *) state;
X 	req->complete = 0;
-
+	
X 	ret = -EFAULT;
X 	if (copy_from_user(req->data, buf, count))
X 		goto out;
X 
X 	atomic_inc(&state->n_pending);
-	switch (adb_hardware) {
-	case ADB_NONE:
-		ret = -ENXIO;
-		break;
-	case ADB_VIACUDA:
-		req->reply_expected = 1;
-		ret = cuda_send_request(req);
-		break;
-	case ADB_VIAPMU:
-		if (req->data[0] != ADB_PACKET) {
-			ret = pmu_send_request(req);
-			break;
-		}
-		/* else fall through */
-	default:
-		ret = -EINVAL;
-		if (req->data[0] != ADB_PACKET)
-			break;
-		for (i = 0; i < req->nbytes-1; ++i)
-			req->data[i] = req->data[i+1];
-		req->nbytes--;
-		req->reply_expected = ((req->data[0] & 0xc) == 0xc);
-		ret = adb_send_request(req, 0);
-		break;
+
+	/* 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))
+		ret = adb_reset_bus();
+	else
+	{	
+		req->reply_expected = ((req->data[1] & 0xc) == 0xc);
+
+		if (adb_controller && adb_controller->send_request)
+			ret = adb_controller->send_request(req, 0);
+		else
+			ret = -ENXIO;
X 	}
X 
X 	if (ret != 0) {
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.2.7/linux/drivers/macintosh/mac_keyb.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/macintosh/mac_keyb.c	Thu Apr 29 12:53:48 1999
@@ -7,6 +7,27 @@
X  * (see that file for its authors and contributors).
X  *
X  * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Adapted to ADB changes and support for more devices by
+ * Benjamin Herrenschmidt. Adapted from code in MkLinux
+ * and reworked.
+ *
+ * Supported devices:
+ *
+ * - Standard 1 button mouse
+ * - All standard Apple Extended protocol (handler ID 4)
+ *   mice & trackballs
+ * - PowerBook Trackpad (default setup: enable tapping)
+ * - MicroSpeed mouse & trackball (needs testing)
+ * - CH Products Trackball Pro (needs testing)
+ * - Contour Design (Contour Mouse)
+ * - Hunter digital (NoHandsMouse)
+ * - Kensignton TurboMouse 5 (needs testing)
+ *
+ * To do:
+ *
+ * Improve Kensignton support, add MacX support as a dynamic
+ * option (not a compile-time option).
X  */
X 
X #include <linux/sched.h>
@@ -32,6 +53,41 @@
X #define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
X #define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
X 
+static int adb_message_handler(struct notifier_block *, unsigned long, void *);
+static struct notifier_block mackeyb_adb_notifier = {
+	adb_message_handler,
+	NULL,
+	0
+};
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
+	0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128] =
+	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
+	"yt123465=97-80o]"				/* 0x10 - 0x1f */
+	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
+	"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
+							/* 0x30 - 0x3f */
+	"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
+							/* 0x40 - 0x4f */
+	"\000\0000123456789\000\000\000"		/* 0x50 - 0x5f */
+	"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
+							/* 0x60 - 0x6f */
+#endif
+
X static u_short macplain_map[NR_KEYS] __initdata = {
X 	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
X 	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
@@ -170,6 +226,8 @@
X static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
X static int last_keycode;
X 
+static void mackeyb_probe(void);
+
X static void keyboard_input(unsigned char *, int, struct pt_regs *, int);
X static void input_keycode(int, int);
X static void leds_done(struct adb_request *);
@@ -180,6 +238,7 @@
X static void init_trackpad(int id);
X static void init_trackball(int id);
X static void init_turbomouse(int id);
+static void init_microspeed(int id);
X 
X #ifdef CONFIG_ADBMOUSE
X /* XXX: Hook for mouse driver */
@@ -207,21 +266,11 @@
X #define ADBMOUSE_TRACKBALL	3	/* TrackBall (handler 4) */
X #define ADBMOUSE_TRACKPAD       4	/* Apple's PowerBook trackpad (handler 4) */
X #define ADBMOUSE_TURBOMOUSE5    5	/* Turbomouse 5 (previously req. mousehack) */
+#define ADBMOUSE_MICROSPEED	6	/* Microspeed mouse (&trackball ?), MacPoint */
+#define ADBMOUSE_TRACKBALLPRO	7	/* Trackball Pro (special buttons) */
X 
X static int adb_mouse_kinds[16];
X 
-/* this map indicates which keys shouldn't autorepeat. */
-static unsigned char dont_repeat[128] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
-	0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
X __openfirmware
X 
X int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
@@ -281,6 +330,10 @@
X 	/* on the powerbook 3400, the power key gives code 0x7e */
X 	if (keycode == 0x7e)
X 		keycode = 0x7f;
+	/* remap the "Fn" key of the PowerBook G3 Series to 0x48
+	   to avoid conflict with button emulation */
+	if (keycode == 0x3f)
+		keycode = 0x48;
X 
X 	if (!repeat)
X 		del_timer(&repeat_timer);
@@ -441,9 +494,24 @@
X 	         the first (the real) button is released. We could do
X 		 this here using async flush requests.
X 	*/
-	if (adb_mouse_kinds[(data[0]>>4) & 0xf] == ADBMOUSE_TRACKPAD) {
+	switch (adb_mouse_kinds[(data[0]>>4) & 0xf])
+	{
+	    case ADBMOUSE_TRACKPAD:
X 		data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
-		data[2] = (data[2] & 0x7f) | 0x80;
+		data[2] = data[2] | 0x80;
+		break;
+	    case ADBMOUSE_MICROSPEED:
+		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
+			| (data[3] & 0x08);
+		break;
+	    case ADBMOUSE_TRACKBALLPRO:
+		data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
+			& ((data[3] & 0x08) << 4));
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
+		break;
X 	}
X 
X 	if (adb_mouse_interrupt_hook)
@@ -473,7 +541,7 @@
X 		}
X 
X 		/* Macintosh 3-button mouse (handler 4). */
-		if (nb == 4) {
+		if (nb >= 4) {
X 			static unsigned char uch_ButtonStateThird = 0x80;
X 			unsigned char uchButtonThird;
X 
@@ -608,9 +676,6 @@
X 
X __initfunc(void mackbd_init_hw(void))
X {
-	struct adb_request req;
-	int i;
-
X 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
X 	    return;
X 
@@ -626,71 +691,127 @@
X #ifdef CONFIG_ADBMOUSE
X 	/* initialize mouse interrupt hook */
X 	adb_mouse_interrupt_hook = NULL;
+#endif
+
+	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)
+{
+	switch (code) {
+	case ADB_MSG_PRE_RESET:
+	case ADB_MSG_POWERDOWN:
+		/* Add unregister_keyboard when merging with Paul Mackerras */
+		while(!led_request.complete)
+			adb_poll();
+		break;
+			
+	case ADB_MSG_POST_RESET:
+		mackeyb_probe();
+		break;
+	}
+	return NOTIFY_DONE;
+}
X 
+static void
+mackeyb_probe(void)
+{
+	struct adb_request req;
+	int i;
+
+#ifdef CONFIG_ADBMOUSE
X 	adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input);
X #endif /* CONFIG_ADBMOUSE */
X 
X 	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
X 	adb_register(0x07, 0x1F, &buttons_ids, buttons_input);
X 
-	for(i = 0; i < keyboard_ids.nids; i++) {
-	    /* turn off all leds */
-	    adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff);
-	}
+	for (i = 0; i < keyboard_ids.nids; i++) {
+		int id = keyboard_ids.id[i];
X 
-	/* Enable full feature set of the keyboard
-	   ->get it to send separate codes for left and right shift,
-	   control, option keys */
-	for(i = 0;i < keyboard_ids.nids; i++) {
-	    if (adb_try_handler_change(keyboard_ids.id[i], 5))
-	    	printk("ADB keyboard at %d, handler set to 5\n", keyboard_ids.id[i]);
-	    else if (adb_try_handler_change(keyboard_ids.id[i], 3))
-	    	printk("ADB keyboard at %d, handler set to 3\n", keyboard_ids.id[i]);
-	    else
-	    	printk("ADB keyboard at %d, handler 1\n", keyboard_ids.id[i]);
+		/* turn off all leds */
+		adb_request(&req, NULL, ADBREQ_SYNC, 3,
+			    ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
+
+		/* Enable full feature set of the keyboard
+		   ->get it to send separate codes for left and right shift,
+		   control, option keys */
+		if (adb_try_handler_change(id, 5))
+			printk("ADB keyboard at %d, handler set to 5\n", id);
+		else if (adb_try_handler_change(id, 3))
+			printk("ADB keyboard at %d, handler set to 3\n", id);
+		else
+			printk("ADB keyboard at %d, handler 1\n", id);
X 	}
X 
-	led_request.complete = 1;
-
X 	/* Try to switch all mice to handler 4, or 2 for three-button
X 	   mode and full resolution. */
-	for(i = 0; i < mouse_ids.nids; i++) {
-            if (adb_try_handler_change(mouse_ids.id[i], 4)) {
-                printk("ADB mouse at %d, handler set to 4", mouse_ids.id[i]);
-	        adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_EXTENDED;
-            }
-	    else if (adb_try_handler_change(mouse_ids.id[i], 2)) {
-	        printk("ADB mouse at %d, handler set to 2", mouse_ids.id[i]);
-	        adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_STANDARD_200;
-	    }
-	    else {
-                printk("ADB mouse at %d, handler 1", mouse_ids.id[i]);
-                adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_STANDARD_100;
-            }
-
-	    /* Register 1 is usually used for device identification.
-	       Here, we try to identify a known device and call the
-	       appropriate init function */
-	    adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-			ADB_READREG(mouse_ids.id[i], 1));
-
-            if ((req.reply_len) &&
-                (req.reply[1] == 0x9a) && (req.reply[2] == 0x21))
-                init_trackball(mouse_ids.id[i]);
-            else if ((req.reply_len >= 4) &&
-		(req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
-		(req.reply[3] == 0x61) && (req.reply[4] == 0x64))
-		init_trackpad(mouse_ids.id[i]);
-	    else if ((req.reply_len >= 4) &&
-		(req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
-		(req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
-		init_turbomouse(mouse_ids.id[i]);
-            printk("\n");
+	for (i = 0; i < mouse_ids.nids; i++) {
+		int id = mouse_ids.id[i];
+		if (adb_try_handler_change(id, 4)) {
+			printk("ADB mouse at %d, handler set to 4", id);
+			adb_mouse_kinds[id] = ADBMOUSE_EXTENDED;
+		}
+		else if (adb_try_handler_change(id, 2)) {
+			printk("ADB mouse at %d, handler set to 2", id);
+			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200;
+		}
+		else if (adb_try_handler_change(id, 0x2F)) {
+			printk("ADB mouse at %d, handler set to 0x2F", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x42)) {
+			printk("ADB mouse at %d, handler set to 0x42", id);
+			adb_mouse_kinds[id] = ADBMOUSE_TRACKBALLPRO;
+		}
+		else if (adb_try_handler_change(id, 0x66)) {
+			printk("ADB mouse at %d, handler set to 0x66", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x5F)) {
+			printk("ADB mouse at %d, handler set to 0x5F", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else {
+			printk("ADB mouse at %d, handler 1", id);
+			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_100;
+		}
+
+		if ((adb_mouse_kinds[id] == ADBMOUSE_TRACKBALLPRO)
+		    || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
+			init_microspeed(id);
+		}  else if (adb_mouse_kinds[id] ==  ADBMOUSE_EXTENDED) {
+			/*
+			 * Register 1 is usually used for device
+			 * identification.  Here, we try to identify
+			 * a known device and call the appropriate
+			 * init function.
+			 */
+			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+				    ADB_READREG(id, 1));
+
+			if ((req.reply_len) &&
+			    (req.reply[1] == 0x9a) && (req.reply[2] == 0x21))
+				init_trackball(id);
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
+			    (req.reply[3] == 0x61) && (req.reply[4] == 0x64))
+				init_trackpad(id);
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
+			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
+				init_turbomouse(id);
+		}
+		printk("\n");
X         }
X }
X 
-__init static void 
+static void 
X init_trackpad(int id)
X {
X 	struct adb_request req;	
@@ -716,7 +837,7 @@
X 	            r1_buffer[4],
X 	            r1_buffer[5],
X 	            0x0d, /*r1_buffer[6],*/
-	           r1_buffer[7]);
+	            r1_buffer[7]);
X 
X             adb_request(&req, NULL, ADBREQ_SYNC, 9,
X 	        ADB_WRITEREG(id,2),
@@ -742,7 +863,7 @@
X         }
X }
X 
-__init static void 
+static void 
X init_trackball(int id)
X {
X 	struct adb_request req;
@@ -776,7 +897,7 @@
X 	ADB_WRITEREG(id,1), 03,0x38);
X }
X 
-__init static void
+static void
X init_turbomouse(int id)
X {
X 	struct adb_request req;
@@ -785,6 +906,13 @@
X 
X 	adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
X 	
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+		ADB_WRITEREG(id,3), 0x20 | id, 4);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
X 	adb_request(&req, NULL, ADBREQ_SYNC, 9,
X 	ADB_WRITEREG(id,2),
X 	    0xe7,
@@ -809,3 +937,44 @@
X 	    0xff,
X 	    0x27);
X }
+
+static void
+init_microspeed(int id)
+{
+	struct adb_request req;
+
+        printk(" (Microspeed/MacPoint or compatible)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	/* This will initialize mice using the Microspeed, MacPoint and
+	   other compatible firmware. Bit 12 enables extended protocol.
+	   
+	   Register 1 Listen (4 Bytes)
+            0 -  3     Button is mouse (set also for double clicking!!!)
+            4 -  7     Button is locking (affects change speed also)
+            8 - 11     Button changes speed
+           12          1 = Extended mouse mode, 0 = normal mouse mode
+           13 - 15     unused 0
+           16 - 23     normal speed
+           24 - 31     changed speed
+
+       Register 1 talk holds version and product identification information.
+       Register 1 Talk (4 Bytes):
+            0 -  7     Product code
+            8 - 23     undefined, reserved
+           24 - 31     Version number
+        
+       Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
+ */
+	adb_request(&req, NULL, ADBREQ_SYNC, 5,
+	ADB_WRITEREG(id,1),
+	    0x20,	/* alt speed = 0x20 (rather slow) */
+	    0x00,	/* norm speed = 0x00 (fastest) */
+	    0x10,	/* extended protocol, no speed change */
+	    0x07);	/* all buttons enabled as mouse buttons, no locking */
+
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c
--- v2.2.7/linux/drivers/macintosh/macio-adb.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/macio-adb.c	Thu Apr 29 12:53:48 1999
@@ -63,9 +63,17 @@
X static int macio_adb_send_request(struct adb_request *req, int sync);
X static int macio_adb_autopoll(int devs);
X static void macio_adb_poll(void);
-static int macio_reset_bus(void);
+static int macio_adb_reset_bus(void);
X static void completed(void);
X 
+static struct adb_controller	macio_controller = {
+	ADB_MACIO,
+	macio_adb_send_request,
+	macio_adb_autopoll,
+	macio_adb_reset_bus,
+	macio_adb_poll
+};
+
X __openfirmware
X 
X void macio_adb_init(void)
@@ -106,10 +114,12 @@
X 	out_8(&adb->autopoll.r, APE);
X 	out_8(&adb->intr_enb.r, DFB | TAG);
X 
-	adb_hardware = ADB_MACIO;
-	adb_send_request = macio_adb_send_request;
-	adb_autopoll = macio_adb_autopoll;
-	adb_reset_bus = macio_reset_bus;
+	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;
X }
X 
X static int macio_adb_autopoll(int devs)
@@ -120,7 +130,7 @@
X 	return 0;
X }
X 
-static int macio_reset_bus(void)
+static int macio_adb_reset_bus(void)
X {
X 	int timeout = 1000000;
X 
@@ -138,7 +148,15 @@
X static int macio_adb_send_request(struct adb_request *req, int sync)
X {
X 	unsigned long mflags;
-
+	int i;
+	
+	if (req->data[0] != ADB_PACKET)
+		return -EINVAL;
+	
+	for (i = 0; i < req->nbytes - 1; ++i)
+		req->data[i] = req->data[i+1];
+	--req->nbytes;
+	
X 	req->next = 0;
X 	req->sent = 0;
X 	req->complete = 0;
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.2.7/linux/drivers/macintosh/macserial.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/macintosh/macserial.c	Thu Apr 29 12:53:48 1999
@@ -1986,6 +1986,7 @@
X 		info->line = i;
X 		info->tty = 0;
X 		info->custom_divisor = 16;
+		info->timeout = 0;
X 		info->close_delay = 50;
X 		info->closing_wait = 3000;
X 		info->x_char = 0;
@@ -2058,6 +2059,32 @@
X static void serial_console_write(struct console *co, const char *s,
X 				 unsigned count)
X {
+	struct mac_serial *info = zs_soft + co->index;
+	int i;
+
+	/* Turn of interrupts and enable the transmitter. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB);
+	write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR);
+
+	for (i=0; i<count; i++) {
+		/* Wait for the transmit buffer to empty. */
+		while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
+			eieio();
+		}
+
+		write_zsdata(info->zs_channel, s[i]);
+		if (s[i] == 10) {
+			while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
+                                == 0)
+				eieio();
+			
+			write_zsdata(info->zs_channel, 13);
+		}
+	}
+
+	/* Restore the values in the registers. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1]);
+	/* Don't disable the transmitter. */
X }
X 
X /*
@@ -2065,7 +2092,23 @@
X  */
X static int serial_console_wait_key(struct console *co)
X {
-	return 0;
+	struct mac_serial *info = zs_soft + co->index;
+	int           val;
+
+	/* Turn of interrupts and enable the transmitter. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~INT_ALL_Rx);
+	write_zsreg(info->zs_channel, R3, info->curregs[3] | RxENABLE);
+
+	/* Wait for something in the receive buffer. */
+	while((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0)
+		eieio();
+	val = read_zsdata(info->zs_channel);
+
+	/* Restore the values in the registers. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1]);
+	write_zsreg(info->zs_channel, R3, info->curregs[3]);
+
+	return val;
X }
X 
X static kdev_t serial_console_device(struct console *c)
@@ -2081,14 +2124,24 @@
X  */
X __initfunc(static int serial_console_setup(struct console *co, char *options))
X {
-	struct serial_state *ser;
-	unsigned cval;
-	int	baud = 9600;
+	struct mac_serial *info = zs_soft + co->index;
+	int	baud = 38400;
X 	int	bits = 8;
X 	int	parity = 'n';
X 	int	cflag = CREAD | HUPCL | CLOCAL;
-	int	quot = 0;
+	int	brg;
X 	char	*s;
+	long	flags;
+
+	/* Find out how many Z8530 SCCs we have */
+	if (zs_chain == 0)
+		probe_sccs();
+
+	if (zs_chain == 0)
+		return -1;
+
+	/* Reset the channel */
+	write_zsreg(info->zs_channel, R9, CHRA);
X 
X 	if (options) {
X 		baud = simple_strtoul(options, NULL, 10);
@@ -2114,21 +2167,21 @@
X 	case 4800:
X 		cflag |= B4800;
X 		break;
+	case 9600:
+		cflag |= B9600;
+		break;
X 	case 19200:
X 		cflag |= B19200;
X 		break;
-	case 38400:
-		cflag |= B38400;
-		break;
X 	case 57600:
X 		cflag |= B57600;
X 		break;
X 	case 115200:
X 		cflag |= B115200;
X 		break;
-	case 9600:
+	case 38400:
X 	default:
-		cflag |= B9600;
+		cflag |= B38400;
X 		break;
X 	}
X 	switch(bits) {
@@ -2142,7 +2195,7 @@
X 	}
X 	switch(parity) {
X 	case 'o': case 'O':
-		cflag |= PARODD;
+		cflag |= PARENB | PARODD;
X 		break;
X 	case 'e': case 'E':
X 		cflag |= PARENB;
@@ -2150,6 +2203,90 @@
X 	}
X 	co->cflag = cflag;
X 
+	save_flags(flags); cli();
+        memset(info->curregs, 0, sizeof(info->curregs));
+
+	info->zs_baud = baud;
+	info->clk_divisor = 16;
+	switch (info->zs_baud) {
+	case ZS_CLOCK/16:	/* 230400 */
+		info->curregs[4] = X16CLK;
+		info->curregs[11] = 0;
+		break;
+	case ZS_CLOCK/32:	/* 115200 */
+		info->curregs[4] = X32CLK;
+		info->curregs[11] = 0;
+		break;
+	default:
+		info->curregs[4] = X16CLK;
+		info->curregs[11] = TCBR | RCBR;
+		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+		info->curregs[12] = (brg & 255);
+		info->curregs[13] = ((brg >> 8) & 255);
+		info->curregs[14] = BRENABL;
+	}
+
+	/* byte size and parity */
+	info->curregs[3] &= ~RxNBITS_MASK;
+	info->curregs[5] &= ~TxNBITS_MASK;
+	switch (cflag & CSIZE) {
+	case CS5:
+		info->curregs[3] |= Rx5;
+		info->curregs[5] |= Tx5;
+		break;
+	case CS6:
+		info->curregs[3] |= Rx6;
+		info->curregs[5] |= Tx6;
+		break;
+	case CS7:
+		info->curregs[3] |= Rx7;
+		info->curregs[5] |= Tx7;
+		break;
+	case CS8:
+	default: /* defaults to 8 bits */
+		info->curregs[3] |= Rx8;
+		info->curregs[5] |= Tx8;
+		break;
+	}
+        info->curregs[5] |= TxENAB | RTS | DTR;
+	info->pendregs[3] = info->curregs[3];
+	info->pendregs[5] = info->curregs[5];
+
+	info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+	if (cflag & CSTOPB) {
+		info->curregs[4] |= SB2;
+	} else {
+		info->curregs[4] |= SB1;
+	}
+	if (cflag & PARENB) {
+		info->curregs[4] |= PAR_ENA;
+		if (!(cflag & PARODD)) {
+			info->curregs[4] |= PAR_EVEN;
+		}
+	}
+	info->pendregs[4] = info->curregs[4];
+
+	if (!(cflag & CLOCAL)) {
+		if (!(info->curregs[15] & DCDIE))
+			info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+		info->curregs[15] |= DCDIE;
+	} else
+		info->curregs[15] &= ~DCDIE;
+	if (cflag & CRTSCTS) {
+		info->curregs[15] |= CTSIE;
+		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+			info->tx_stopped = 1;
+	} else {
+		info->curregs[15] &= ~CTSIE;
+		info->tx_stopped = 0;
+	}
+	info->pendregs[15] = info->curregs[15];
+
+	/* Load up the new values */
+	load_zsregs(info->zs_channel, info->curregs);
+
+	restore_flags(flags);
+
X 	return 0;
X }
X 
@@ -2170,9 +2307,10 @@
X /*
X  *	Register console.
X  */
-__initfunc (void serial_console_init(void))
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
X {
X 	register_console(&sercons);
+	return kmem_start;
X }
X #endif /* ifdef CONFIG_SERIAL_CONSOLE */
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c
--- v2.2.7/linux/drivers/macintosh/nvram.c	Wed Aug 26 11:37:38 1998
+++ linux/drivers/macintosh/nvram.c	Thu Apr 29 12:53:48 1999
@@ -1,6 +1,11 @@
X /*
X  * /dev/nvram driver for Power Macintosh.
X  */
+
+#define NVRAM_VERSION "1.0"
+
+#include <linux/module.h>
+
X #include <linux/types.h>
X #include <linux/errno.h>
X #include <linux/fs.h>
@@ -9,11 +14,14 @@
X #include <linux/nvram.h>
X #include <linux/init.h>
X #include <asm/uaccess.h>
-#include <asm/init.h>
X 
X #define NVRAM_SIZE	8192
X 
+/* when building as a module, __openfirmware is both unavailable
+ * and unnecessary. */
+#ifndef MODULE
X __openfirmware
+#endif
X 
X static long long nvram_llseek(struct file *file, loff_t offset, int origin)
X {
@@ -70,6 +78,13 @@
X 
X static int nvram_open(struct inode *inode, struct file *file)
X {
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int nvram_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
X 	return 0;
X }
X 
@@ -83,7 +98,7 @@
X 	NULL,		/* nvram_mmap */
X 	nvram_open,
X 	NULL,		/* flush */
-	NULL,		/* no special release code */
+	nvram_release,
X 	NULL		/* fsync */
X };
X 
@@ -95,6 +110,19 @@
X 
X __initfunc(int nvram_init(void))
X {
+	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
+		NVRAM_VERSION);
X 	misc_register(&nvram_dev);
X 	return 0;
X }
+#ifdef MODULE
+int init_module (void)
+{
+        return( nvram_init() );
+}
+
+void cleanup_module (void)
+{
+        misc_deregister( &nvram_dev );
+}
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.2.7/linux/drivers/macintosh/via-cuda.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/via-cuda.c	Thu Apr 29 12:53:48 1999
@@ -74,6 +74,7 @@
X static int reading_reply;
X static int data_index;
X static struct device_node *vias;
+static int cuda_fully_inited = 0;
X 
X static int init_via(void);
X static void cuda_start(void);
@@ -81,7 +82,17 @@
X static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
X static int cuda_adb_send_request(struct adb_request *req, int sync);
X static int cuda_adb_autopoll(int devs);
-static int cuda_reset_bus(void);
+static int cuda_adb_reset_bus(void);
+static int cuda_send_request(struct adb_request *req);
+
+
+static struct adb_controller	cuda_controller = {
+	ADB_VIACUDA,
+	cuda_adb_send_request,
+	cuda_adb_autopoll,
+	cuda_adb_reset_bus,
+	cuda_poll
+};
X 
X __openfirmware
X 
@@ -121,7 +132,7 @@
X 	via = NULL;
X     }
X 
-    adb_hardware = ADB_VIACUDA;
+   adb_controller = &cuda_controller;
X }
X 
X void
@@ -139,10 +150,7 @@
X     via[IFR] = 0x7f; eieio();	/* clear interrupts by writing 1s */
X     via[IER] = IER_SET|SR_INT; eieio();	/* enable interrupt from SR */
X 
-    /* Set function pointers */
-    adb_send_request = cuda_adb_send_request;
-    adb_autopoll = cuda_adb_autopoll;
-    adb_reset_bus = cuda_reset_bus;
+    cuda_fully_inited = 1;
X }
X 
X #define WAIT_FOR(cond, what)				\
@@ -201,14 +209,17 @@
X {
X     int i;
X 
-    for (i = req->nbytes; i > 0; --i)
-	req->data[i] = req->data[i-1];
-    req->data[0] = ADB_PACKET;
-    ++req->nbytes;
+    if ((via == NULL) || !cuda_fully_inited) {
+	req->complete = 1;
+	return -ENXIO;
+    }
+  
X     req->reply_expected = 1;
+
X     i = cuda_send_request(req);
X     if (i)
X 	return i;
+
X     if (sync) {
X 	while (!req->complete)
X 	    cuda_poll();
@@ -216,12 +227,16 @@
X     return 0;
X }
X 
+
X /* Enable/disable autopolling */
X static int
X cuda_adb_autopoll(int devs)
X {
X     struct adb_request req;
X 
+    if ((via == NULL) || !cuda_fully_inited)
+	return -ENXIO;
+
X     cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0));
X     while (!req.complete)
X 	cuda_poll();
@@ -230,10 +245,13 @@
X 
X /* Reset adb bus - how do we do this?? */
X static int
-cuda_reset_bus(void)
+cuda_adb_reset_bus(void)
X {
X     struct adb_request req;
X 
+    if ((via == NULL) || !cuda_fully_inited)
+	return -ENXIO;
+
X     cuda_request(&req, NULL, 2, ADB_PACKET, 0);		/* maybe? */
X     while (!req.complete)
X 	cuda_poll();
@@ -248,6 +266,11 @@
X     va_list list;
X     int i;
X 
+    if (via == NULL) {
+	req->complete = 1;
+	return -ENXIO;
+    }
+
X     req->nbytes = nbytes;
X     req->done = done;
X     va_start(list, nbytes);
@@ -258,15 +281,11 @@
X     return cuda_send_request(req);
X }
X 
-int
+static int
X cuda_send_request(struct adb_request *req)
X {
X     unsigned long flags;
X 
-    if (via == NULL) {
-	req->complete = 1;
-	return -ENXIO;
-    }
X     if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
X 	req->complete = 1;
X 	return -EINVAL;
@@ -472,3 +491,9 @@
X 	printk("\n");
X     }
X }
+
+int
+cuda_present(void)
+{
+	return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
+}
\ No newline at end of file
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.2.7/linux/drivers/macintosh/via-pmu.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/macintosh/via-pmu.c	Thu Apr 29 12:53:48 1999
@@ -93,6 +93,7 @@
X static struct adb_request bright_req_1, bright_req_2, bright_req_3;
X static struct device_node *vias;
X static int pmu_kind = PMU_UNKNOWN;
+static int pmu_fully_inited = 0;
X 
X int asleep;
X struct notifier_block *sleep_notifier_list;
@@ -103,7 +104,7 @@
X static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
X static int pmu_adb_send_request(struct adb_request *req, int sync);
X static int pmu_adb_autopoll(int devs);
-static int pmu_reset_bus(void);
+static int pmu_adb_reset_bus(void);
X static void send_byte(int x);
X static void recv_byte(void);
X static void pmu_sr_intr(struct pt_regs *regs);
@@ -112,6 +113,14 @@
X 			    struct pt_regs *regs);
X static void set_volume(int level);
X 
+static struct adb_controller	pmu_controller = {
+	ADB_VIAPMU,
+	pmu_adb_send_request,
+	pmu_adb_autopoll,
+	pmu_adb_reset_bus,
+	pmu_poll
+};
+
X /*
X  * This table indicates for each PMU opcode:
X  * - the number of data bytes to be sent with the command, or -1
@@ -126,17 +135,17 @@
X /*10*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
X /*18*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
X /*20*/	{-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*28*/	{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*30*/	{ 4, 0},{20, 0},{ 2, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*38*/	{ 0, 4},{ 0,20},{ 1, 1},{ 2, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*28*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
+/*30*/	{ 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*38*/	{ 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
X /*40*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*48*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
+/*48*/	{ 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
X /*50*/	{ 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
X /*58*/	{ 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
-/*60*/	{ 2, 0},{-1, 0},{ 2, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*60*/	{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
X /*68*/	{ 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
X /*70*/	{ 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*78*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 4, 1},{ 4, 1},
+/*78*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
X /*80*/	{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
X /*88*/	{ 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
X /*90*/	{ 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
@@ -149,7 +158,7 @@
X /*c8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
X /*d0*/	{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
X /*d8*/	{ 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
-/*e0*/	{-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*e0*/	{-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
X /*e8*/	{ 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
X /*f0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
X /*f8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
@@ -186,8 +195,8 @@
X 			return;
X 	}
X 
-	if (vias->parent->name && strcmp(vias->parent->name, "ohare") == 0
-	    || device_is_compatible(vias->parent, "ohare"))
+	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
+	    || device_is_compatible(vias->parent, "ohare")))
X 		pmu_kind = PMU_OHARE_BASED;
X 	else if (device_is_compatible(vias->parent, "heathrow"))
X 		pmu_kind = PMU_HEATHROW_BASED;
@@ -203,13 +212,13 @@
X 	if (!init_pmu())
X 		via = NULL;
X 
-	adb_hardware = ADB_VIAPMU;
-	
+	adb_controller = &pmu_controller;
+
X 	if (via)
X 		printk(KERN_INFO "PMU driver initialized for %s\n",
-		(pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
-		((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
-		"Unknown PowerBook"));
+		    (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
+		    ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
+		    "Unknown PowerBook"));
X }
X 
X void __openfirmware
@@ -232,11 +241,8 @@
X 	/* Enable interrupts */
X 	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
X 
-	/* Set function pointers */
-	adb_send_request = pmu_adb_send_request;
-	adb_autopoll = pmu_adb_autopoll;
-	adb_reset_bus = pmu_reset_bus;
-
+	pmu_fully_inited = 1;
+	
X 	/* Enable backlight */
X 	pmu_enable_backlight(1);
X }
@@ -288,25 +294,81 @@
X static int __openfirmware
X pmu_adb_send_request(struct adb_request *req, int sync)
X {
-	int i;
+    int i, ret;
X 
-	for (i = req->nbytes - 1; i > 0; --i)
-		req->data[i+3] = req->data[i];
-	req->data[3] = req->nbytes - 1;
-	req->data[2] = pmu_adb_flags;
-	req->data[1] = req->data[0];
-	req->data[0] = PMU_ADB_CMD;
-	req->nbytes += 3;
-	req->reply_expected = 1;
-	req->reply_len = 0;
-	i = pmu_queue_request(req);
-	if (i)
-		return i;
-	if (sync) {
-		while (!req->complete)
-			pmu_poll();
-	}
-	return 0;
+    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)
+			req->data[i] = req->data[i+1];
+		--req->nbytes;
+		if (pmu_data_len[req->data[0]][1] != 0) {
+			req->reply[0] = ADB_RET_OK;
+			req->reply_len = 1;
+		} else
+			req->reply_len = 0;
+		ret = pmu_queue_request(req);
+		break;
+    case CUDA_PACKET:
+		switch (req->data[1]) {
+		case CUDA_GET_TIME:
+			if (req->nbytes != 2)
+				break;
+			req->data[0] = PMU_READ_RTC;
+			req->nbytes = 1;
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_GET_TIME;
+			ret = pmu_queue_request(req);
+			break;
+		case CUDA_SET_TIME:
+			if (req->nbytes != 6)
+				break;
+			req->data[0] = PMU_SET_RTC;
+			req->nbytes = 5;
+			for (i = 1; i <= 4; ++i)
+				req->data[i] = req->data[i+1];
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_SET_TIME;
+			ret = pmu_queue_request(req);
+			break;
+		}
+		break;
+    case ADB_PACKET:
+		for (i = req->nbytes - 1; i > 1; --i)
+			req->data[i+2] = req->data[i];
+		req->data[3] = req->nbytes - 2;
+		req->data[2] = pmu_adb_flags;
+		/*req->data[1] = req->data[1];*/
+		req->data[0] = PMU_ADB_CMD;
+		req->nbytes += 2;
+		req->reply_expected = 1;
+		req->reply_len = 0;
+		ret = pmu_queue_request(req);
+		break;
+    }
+    if (ret)
+    {
+    	req->complete = 1;
+    	return ret;
+    }
+    	
+    if (sync) {
+	while (!req->complete)
+		pmu_poll();
+    }
+
+    return 0;
X }
X 
X /* Enable/disable autopolling */
@@ -315,6 +377,9 @@
X {
X 	struct adb_request req;
X 
+	if ((vias == NULL) || (!pmu_fully_inited))
+		return -ENXIO;
+
X 	if (devs) {
X 		adb_dev_map = devs;
X 		pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
@@ -331,12 +396,15 @@
X 
X /* Reset the ADB bus */
X static int __openfirmware
-pmu_reset_bus(void)
+pmu_adb_reset_bus(void)
X {
X 	struct adb_request req;
X 	long timeout;
X 	int save_autopoll = adb_dev_map;
X 
+	if ((vias == NULL) || (!pmu_fully_inited))
+		return -ENXIO;
+
X 	/* anyone got a better idea?? */
X 	pmu_adb_autopoll(0);
X 
@@ -344,23 +412,23 @@
X 	req.done = NULL;
X 	req.data[0] = PMU_ADB_CMD;
X 	req.data[1] = 0;
-	req.data[2] = 3;
+	req.data[2] = 3; /* ADB_BUSRESET ??? */
X 	req.data[3] = 0;
X 	req.data[4] = 0;
X 	req.reply_len = 0;
X 	req.reply_expected = 1;
X 	if (pmu_queue_request(&req) != 0)
X 	{
-		printk(KERN_ERR "pmu_reset_bus: pmu_queue_request failed\n");
-		return 0;
+		printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
+		return -EIO;
X 	}
X 	while (!req.complete)
X 		pmu_poll();
X 	timeout = 100000;
X 	while (!req.complete) {
X 		if (--timeout < 0) {
-			printk(KERN_ERR "pmu_reset_bus (reset): no response from PMU\n");
-			return 0;
+			printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
+			return -EIO;
X 		}
X 		udelay(10);
X 		pmu_poll();
@@ -369,7 +437,7 @@
X 	if (save_autopoll != 0)
X 		pmu_adb_autopoll(save_autopoll);
X 		
-	return 1;
+	return 0;
X }
X 
X /* Construct and send a pmu request */
@@ -380,6 +448,9 @@
X 	va_list list;
X 	int i;
X 
+	if (vias == NULL)
+		return -ENXIO;
+
X 	if (nbytes < 0 || nbytes > 32) {
X 		printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
X 		req->complete = 1;
@@ -400,57 +471,6 @@
X 	return pmu_queue_request(req);
X }
X 
-/*
- * This procedure handles requests written to /dev/adb where the
- * first byte is CUDA_PACKET or PMU_PACKET.  For CUDA_PACKET, we
- * emulate a few CUDA requests.
- */
-int __openfirmware
-pmu_send_request(struct adb_request *req)
-{
-	int i;
-
-	switch (req->data[0]) {
-	case PMU_PACKET:
-		for (i = 0; i < req->nbytes - 1; ++i)
-			req->data[i] = req->data[i+1];
-		--req->nbytes;
-		if (pmu_data_len[req->data[0]][1] != 0) {
-			req->reply[0] = ADB_RET_OK;
-			req->reply_len = 1;
-		} else
-			req->reply_len = 0;
-		return pmu_queue_request(req);
-	case CUDA_PACKET:
-		switch (req->data[1]) {
-		case CUDA_GET_TIME:
-			if (req->nbytes != 2)
-				break;
-			req->data[0] = PMU_READ_RTC;
-			req->nbytes = 1;
-			req->reply_len = 3;
-			req->reply[0] = CUDA_PACKET;
-			req->reply[1] = 0;
-			req->reply[2] = CUDA_GET_TIME;
-			return pmu_queue_request(req);
-		case CUDA_SET_TIME:
-			if (req->nbytes != 6)
-				break;
-			req->data[0] = PMU_SET_RTC;
-			req->nbytes = 5;
-			for (i = 1; i <= 4; ++i)
-				req->data[i] = req->data[i+1];
-			req->reply_len = 3;
-			req->reply[0] = CUDA_PACKET;
-			req->reply[1] = 0;
-			req->reply[2] = CUDA_SET_TIME;
-			return pmu_queue_request(req);
-		}
-		break;
-	}
-	return -EINVAL;
-}
-
X int __openfirmware
X pmu_queue_request(struct adb_request *req)
X {
@@ -737,7 +757,7 @@
X {
X 	struct adb_request req;
X 
-	if (adb_hardware != ADB_VIAPMU)
+	if (vias == NULL)
X 		return ;
X 		
X 	if (on) {
@@ -780,7 +800,7 @@
X {
X 	int bright;
X 
-	if (adb_hardware != ADB_VIAPMU)
+	if (vias == NULL)
X 		return ;
X 
X 	backlight_level = level;
@@ -807,7 +827,7 @@
X {
X 	struct adb_request req;
X 
-	if (adb_hardware != ADB_VIAPMU)
+	if (vias == NULL)
X 		return ;
X 
X 	pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
@@ -860,6 +880,11 @@
X 		;
X }
X 
+int
+pmu_present(void)
+{
+	return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+}
X 
X #ifdef CONFIG_PMAC_PBOOK
X 
@@ -1104,3 +1129,4 @@
X 		misc_register(&pmu_device);
X }
X #endif /* CONFIG_PMAC_PBOOK */
+
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/Makefile linux/drivers/misc/Makefile
--- v2.2.7/linux/drivers/misc/Makefile	Fri Jan  8 22:36:06 1999
+++ linux/drivers/misc/Makefile	Tue May 11 09:55:49 1999
@@ -34,6 +34,27 @@
X       M_OBJS += parport_ax.o
X     endif
X   endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),y)
+    LX_OBJS += parport_amiga.o
+  else
+    ifeq ($(CONFIG_PARPORT_AMIGA),m)
+      M_OBJS += parport_amiga.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),y)
+    LX_OBJS += parport_mfc3.o
+  else
+    ifeq ($(CONFIG_PARPORT_MFC3),m)
+      M_OBJS += parport_mfc3.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),y)
+    LX_OBJS += parport_atari.o
+  else
+    ifeq ($(CONFIG_PARPORT_ATARI),m)
+      M_OBJS += parport_atari.o
+    endif
+  endif
X   LX_OBJS += parport_init.o
X else
X   ifeq ($(CONFIG_PARPORT),m)
@@ -49,6 +70,15 @@
X   endif
X   ifeq ($(CONFIG_PARPORT_AX),m)
X     M_OBJS += parport_ax.o
+  endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),m)
+    M_OBJS += parport_amiga.o
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),m)
+    M_OBJS += parport_mfc3.o
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),m)
+    M_OBJS += parport_atari.o
X   endif
X endif
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/multiface.h linux/drivers/misc/multiface.h
--- v2.2.7/linux/drivers/misc/multiface.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/multiface.h	Tue May 11 09:55:49 1999
@@ -0,0 +1,20 @@
+#ifndef _MULTIFACE_H_
+#define _MULTIFACE_H_
+
+/*
+ * Defines for SerialMaster, Multiface Card II and Multiface Card III
+ * The addresses given below are offsets to the board base address
+ * 
+ * 6.11.95 Joerg Dorchain (dorc...@mpi-sb.mpg.de)
+ *
+ */
+
+#define PIA_REG_PADWIDTH 255
+
+#define DUARTBASE 0x0000
+#define PITBASE   0x0100
+#define ROMBASE   0x0200
+#define PIABASE   0x4000
+
+#endif
+
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_amiga.c linux/drivers/misc/parport_amiga.c
--- v2.2.7/linux/drivers/misc/parport_amiga.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_amiga.c	Tue May 11 09:55:49 1999
@@ -0,0 +1,322 @@
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorc...@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern. code.
+ *
+ * The built-in Amiga parallel port provides one port at a fixed address
+ * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
+ * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
+ * hardware when the data register is accessed), and 1 input control line
+ * /ACK, able to cause an interrupt, but both not directly settable by
+ * software.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port = NULL;
+
+static void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+	/* Triggers also /STROBE. This behavior cannot be changed */
+	ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 15'
echo 'File patch-2.2.8 is continued in part 16'
echo 16 > _shar_seq_.tmp
#!/bin/sh
# this is part 16 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 16; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+{
+	/* Triggers also /STROBE. This behavior cannot be changed */
+	return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+	unsigned char ret = 0;
+
+	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+		;
+	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+		;
+	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+		;
+	if (control & PARPORT_CONTROL_INIT) /* INITP */
+		/* reset connected to cpu reset pin */;
+	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+		/* Not connected */;
+	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+		/* Handled only directly by hardware */;
+	return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+	return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+	      PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
+	/* fake value: interrupt enable, select in, no reset,
+	no autolf, no strobe - seems to be closest the wiring diagram */
+}
+
+static void amiga_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+	/* No implementation possible */
+}
+	
+static unsigned char amiga_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+	return control_amiga_to_pc(0);
+}
+
+static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+	old = amiga_read_control(p);
+	amiga_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char status_pc_to_amiga(unsigned char status)
+{
+	unsigned char ret = 1;
+
+	if (status & PARPORT_STATUS_BUSY) /* Busy */
+		ret &= ~1;
+	if (status & PARPORT_STATUS_ACK) /* Ack */
+		/* handled in hardware */;
+	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+		ret |= 2;
+	if (status & PARPORT_STATUS_SELECT) /* select */
+		ret |= 4;
+	if (status & PARPORT_STATUS_ERROR) /* error */
+		/* not connected */;
+	return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+	unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
+
+	if (status & 1) /* Busy */
+		ret &= ~PARPORT_STATUS_BUSY;
+	if (status & 2) /* PaperOut */
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (status & 4) /* Selected */
+		ret |= PARPORT_STATUS_SELECT;
+	/* the rest is not connected or handled autonomously in hardware */
+
+	return ret;
+}
+
+static void amiga_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+	ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
+}
+
+static unsigned char amiga_read_status(struct parport *p)
+{
+	unsigned char status;
+
+	status = status_amiga_to_pc(ciab.pra & 7);
+DPRINTK("read_status %02x\n", status);
+	return status;
+}
+
+static void amiga_change_mode( struct parport *p, int m)
+{
+	/* XXX: This port only has one mode, and I am
+	not sure about the corresponding PC-style mode*/
+}
+
+/* as this ports irq handling is already done, we use a generic funktion */
+static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+
+static void amiga_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_AMIGA_CIAA_FLG, p);
+}
+
+static int amiga_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+	return request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p);
+}
+
+static void amiga_init_state(struct parport_state *s)
+{
+	s->u.amiga.data = 0;
+	s->u.amiga.datadir = 255;
+	s->u.amiga.status = 0;
+	s->u.amiga.statusdir = 0;
+}
+
+static void amiga_save_state(struct parport *p, struct parport_state *s)
+{
+	s->u.amiga.data = ciaa.prb;
+	s->u.amiga.datadir = ciaa.ddrb;
+	s->u.amiga.status = ciab.pra & 7;
+	s->u.amiga.statusdir = ciab.ddra & 7;
+}
+
+static void amiga_restore_state(struct parport *p, struct parport_state *s)
+{
+	ciaa.prb = s->u.amiga.data;
+	ciaa.ddrb = s->u.amiga.datadir;
+	ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
+	ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
+}
+
+static void amiga_enable_irq(struct parport *p)
+{
+	enable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_disable_irq(struct parport *p)
+{
+	disable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void amiga_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void amiga_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_amiga_ops = {
+	amiga_write_data,
+	amiga_read_data,
+
+	amiga_write_control,
+	amiga_read_control,
+	amiga_frob_control,
+
+	NULL, /* write_econtrol */
+	NULL, /* read_econtrol */
+	NULL, /* frob_econtrol */
+
+	amiga_write_status,
+	amiga_read_status,
+
+	NULL, /* write fifo */
+	NULL, /* read fifo */
+
+	amiga_change_mode,
+
+
+	amiga_release_resources,
+	amiga_claim_resources,
+
+
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
+	NULL, /* epp_write_block */
+	NULL, /* epp_read_block */
+
+	NULL, /* ecp_write_block */
+	NULL, /* ecp_read_block */
+
+	amiga_init_state,
+	amiga_save_state,
+	amiga_restore_state,
+
+	amiga_enable_irq,
+	amiga_disable_irq,
+	amiga_interrupt, 
+
+	amiga_inc_use_count,
+	amiga_dec_use_count,
+	amiga_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_amiga_init(void))
+{
+	struct parport *p;
+
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+		ciaa.ddrb = 0xff;
+		ciab.ddra &= 0xf8;
+		if (!(p = parport_register_port((unsigned long)&ciaa.prb,
+					IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
+					&pp_amiga_ops)))
+			return 0;
+		this_port = p;
+		printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+		/* XXX: set operating mode */
+		parport_proc_register(p);
+		p->flags |= PARPORT_FLAG_COMA;
+
+		if (parport_probe_hook)
+			(*parport_probe_hook)(p);
+		return 1;
+
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
+MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
+
+int init_module(void)
+{
+	return ! parport_amiga_init();
+}
+
+void cleanup_module(void)
+{
+	if (!(this_port->flags & PARPORT_FLAG_COMA))
+		parport_quiesce(this_port);
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+#endif
+
+
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_atari.c linux/drivers/misc/parport_atari.c
--- v2.2.7/linux/drivers/misc/parport_atari.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_atari.c	Tue May 11 09:55:49 1999
@@ -0,0 +1,263 @@
+/* Low-level parallel port routines for the Atari builtin port
+ *
+ * Author: Andreas Schwab <sch...@issan.informatik.uni-dortmund.de>
+ *
+ * Based on parport_amiga.c.
+ *
+ * The built-in Atari parallel port provides one port at a fixed address
+ * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
+ * and 1 input status line (BUSY) able to cause an interrupt.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/irq.h>
+#include <asm/atariints.h>
+
+static struct parport *this_port = NULL;
+
+static unsigned char
+parport_atari_read_data(struct parport *p)
+{
+	unsigned long flags;
+	unsigned char data;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 15;
+	data = sound_ym.rd_data_reg_sel;
+	restore_flags(flags);
+	return data;
+}
+
+static void
+parport_atari_write_data(struct parport *p, unsigned char data)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 15;
+	sound_ym.wd_data = data;
+	restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_read_control(struct parport *p)
+{
+	unsigned long flags;
+	unsigned char control = 0;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 14;
+	if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
+		control = PARPORT_CONTROL_STROBE;
+	restore_flags(flags);
+	return control;
+}
+
+static void
+parport_atari_write_control(struct parport *p, unsigned char control)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 14;
+	if (control & PARPORT_CONTROL_STROBE)
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
+	else
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+	restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_frob_control(struct parport *p, unsigned char mask,
+			   unsigned char val)
+{
+	unsigned char old = parport_atari_read_control(p);
+	parport_atari_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+static unsigned char
+parport_atari_read_status(struct parport *p)
+{
+	return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
+		PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
+}
+
+static void
+parport_atari_write_status(struct parport *p, unsigned char status)
+{
+}
+
+static void
+parport_atari_init_state(struct parport_state *s)
+{
+}
+
+static void
+parport_atari_save_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_restore_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void
+parport_atari_release_resources(struct parport *p)
+{
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_MFP_BUSY, p);
+}
+
+static int
+parport_atari_claim_resources(struct parport *p)
+{
+	return request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
+			   IRQ_TYPE_SLOW, p->name, p);
+}
+
+static void
+parport_atari_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void
+parport_atari_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void
+parport_atari_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_atari_ops = {
+	parport_atari_write_data,
+	parport_atari_read_data,
+
+	parport_atari_write_control,
+	parport_atari_read_control,
+	parport_atari_frob_control,
+
+	NULL, /* write_econtrol */
+	NULL, /* read_econtrol */
+	NULL, /* frob_econtrol */
+
+	parport_atari_write_status,
+	parport_atari_read_status,
+
+	NULL, /* write fifo */
+	NULL, /* read fifo */
+
+	NULL, /* change_mode */
+
+	parport_atari_release_resources,
+	parport_atari_claim_resources,
+
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
+	NULL, /* epp_write_block */
+	NULL, /* epp_read_block */
+
+	NULL, /* ecp_write_block */
+	NULL, /* ecp_read_block */
+
+	parport_atari_init_state,
+	parport_atari_save_state,
+	parport_atari_restore_state,
+
+	NULL, /* enable_irq */
+	NULL, /* disable_irq */
+	parport_atari_interrupt,
+
+	parport_atari_inc_use_count,
+	parport_atari_dec_use_count,
+	parport_atari_fill_inode
+};
+
+
+int __init
+parport_atari_init(void)
+{
+	struct parport *p;
+	unsigned long flags;
+
+	if (MACH_IS_ATARI) {
+		save_flags(flags);
+		cli();
+		/* Soundchip port A/B as output. */
+		sound_ym.rd_data_reg_sel = 7;
+		sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
+		/* STROBE high. */
+		sound_ym.rd_data_reg_sel = 14;
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+		restore_flags(flags);
+		/* MFP port I0 as input. */
+		mfp.data_dir &= ~1;
+		/* MFP port I0 interrupt on high->low edge. */
+		mfp.active_edge &= ~1;
+		p = parport_register_port((unsigned long)&sound_ym.wd_data,
+					  IRQ_MFP_BUSY, PARPORT_DMA_NONE,
+					  &parport_atari_ops);
+		if (!p)
+			return 0;
+		this_port = p;
+		printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
+		parport_proc_register(p);
+		p->flags |= PARPORT_FLAG_COMA;
+
+		if (parport_probe_hook)
+			(*parport_probe_hook)(p);
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Andreas Schwab");
+MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
+MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
+
+int
+init_module(void)
+{
+	return parport_atari_init() ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+	if (!(this_port->flags & PARPORT_FLAG_COMA))
+		parport_quiesce(this_port);
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.2.7/linux/drivers/misc/parport_ieee1284.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/misc/parport_ieee1284.c	Mon May 10 10:26:31 1999
@@ -48,25 +48,22 @@
X int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) 
X {
X 	/* make sure it's a valid state, set nStrobe & nAutoFeed high */
-	parport_write_control(port, (parport_read_control(port) \
-		& ~1 ) & ~2);
+	parport_frob_control (port, (1|2), 0);
X 	udelay(1);
X 	parport_write_data(port, mode);
X 	udelay(400);
X 	/* nSelectIn high, nAutoFd low */
-	parport_write_control(port, (parport_read_control(port) & ~8) | 2);
+	parport_frob_control(port, (2|8), 2);
X 	if (parport_wait_peripheral(port, 0x78, 0x38)) {
-		parport_write_control(port, 
-				      (parport_read_control(port) & ~2) | 8);
+		parport_frob_control(port, (2|8), 8);
X 		return 0; 
X 	}
X 	/* nStrobe low */
-	parport_write_control(port, parport_read_control(port) | 1);
+	parport_frob_control (port, 1, 1);
X 	udelay(1);				     /* Strobe wait */
X 	/* nStrobe high, nAutoFeed low, last step before transferring 
X 	 *  reverse data */
-	parport_write_control(port, (parport_read_control(port) \
-		& ~1) & ~2);
+	parport_frob_control (port, (1|2), 0);
X 	udelay(1);
X 	/* Data available? */
X 	parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.2.7/linux/drivers/misc/parport_init.c	Mon Jan  4 15:08:17 1999
+++ linux/drivers/misc/parport_init.c	Tue May 11 09:55:49 1999
@@ -126,6 +126,15 @@
X #ifdef CONFIG_PARPORT_AX
X 	parport_ax_init();
X #endif
+#ifdef CONFIG_PARPORT_AMIGA
+	parport_amiga_init();
+#endif
+#ifdef CONFIG_PARPORT_MFC3
+	parport_mfc3_init();
+#endif
+#ifdef CONFIG_PARPORT_ATARI
+	parport_atari_init();
+#endif
X 	return 0;
X }
X #endif
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_mfc3.c linux/drivers/misc/parport_mfc3.c
--- v2.2.7/linux/drivers/misc/parport_mfc3.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/misc/parport_mfc3.c	Tue May 11 09:55:49 1999
@@ -0,0 +1,420 @@
+/* Low-level parallel port routines for the Multiface 3 card
+ *
+ * Author: Joerg Dorchain <dorc...@wirbel.com>
+ *
+ * (C) The elitist m68k Users(TM)
+ *
+ * based on the existing parport_amiga and lp_mfc
+ *
+ *
+ * From the MFC3 documentation:
+ * 
+ * Miscellaneous PIA Details
+ * -------------------------
+ * 
+ * 	The two open-drain interrupt outputs /IRQA and /IRQB are routed to
+ * /INT2 of the Z2 bus.
+ * 
+ * 	The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
+ * bus. This means that any PIA registers are accessed at even addresses.
+ * 
+ * Centronics Pin Connections for the PIA
+ * --------------------------------------
+ * 
+ * 	The following table shows the connections between the PIA and the
+ * Centronics interface connector. These connections implement a single, but
+ * very complete, Centronics type interface. The Pin column gives the pin
+ * numbers of the PIA. The Centronics pin numbers can be found in the section
+ * "Parallel Connectors".
+ * 
+ * 
+ *    Pin | PIA | Dir | Centronics Names
+ * -------+-----+-----+---------------------------------------------------------
+ *     19 | CB2 | --> | /STROBE (aka /DRDY)
+ *  10-17 | PBx | <-> | DATA0 - DATA7
+ *     18 | CB1 | <-- | /ACK
+ *     40 | CA1 | <-- | BUSY
+ *      3 | PA1 | <-- | PAPER-OUT (aka POUT)
+ *      4 | PA2 | <-- | SELECTED (aka SEL)
+ *      9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
+ *      6 | PA4 | <-- | /ERROR (aka /FAULT)
+ *      7 | PA5 | --> | DIR (aka /SELECT-IN)
+ *      8 | PA6 | --> | /AUTO-FEED-XT
+ *     39 | CA2 | --> | open
+ *      5 | PA3 | <-- | /ACK (same as CB1!)
+ *      2 | PA0 | <-- | BUSY (same as CA1!)
+ * -------+-----+-----+---------------------------------------------------------
+ * 
+ * Should be enough to understand some of the driver.
+ */
+
+#include "multiface.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/mc6821.h>
+#include <linux/zorro.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+/* Maximum Number of Cards supported */
+#define MAX_MFC 5
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port[MAX_MFC] = {NULL, };
+static volatile int dummy; /* for trigger readds */
+
+#define pia(dev) ((struct pia *)(dev->base))
+static struct parport_operations pp_mfc3_ops;
+
+static void mfc3_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+
+	dummy = pia(p)->pprb; /* clears irq bit */
+	/* Triggers also /STROBE.*/
+	pia(p)->pprb = data;
+}
+
+static unsigned char mfc3_read_data(struct parport *p)
+{
+	/* clears interupt bit. Triggers also /STROBE. */
+	return pia(p)->pprb;
+}
+
+static unsigned char control_pc_to_mfc3(unsigned char control)
+{
+	unsigned char ret = 32|64;
+
+	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+		;
+	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+		;
+	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+		ret &= ~32; /* /SELECT_IN */
+	if (control & PARPORT_CONTROL_INIT) /* INITP */
+		ret |= 128;
+	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+		ret &= ~64;
+	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+		/* Handled directly by hardware */;
+	return ret;
+}
+
+static unsigned char control_mfc3_to_pc(unsigned char control)
+{
+	unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE 
+			  | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+
+	if (control & 128) /* /INITP */
+		ret |= PARPORT_CONTROL_INIT;
+	if (control & 64) /* /AUTOLF */
+		ret &= ~PARPORT_CONTROL_AUTOFD;
+	if (control & 32) /* /SELECT_IN */
+		ret &= ~PARPORT_CONTROL_SELECT;
+	return ret;
+}
+
+static void mfc3_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+	pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
+}
+	
+static unsigned char mfc3_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+	return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
+}
+
+static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+	old = mfc3_read_control(p);
+	mfc3_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char status_pc_to_mfc3(unsigned char status)
+{
+	unsigned char ret = 1;
+
+	if (status & PARPORT_STATUS_BUSY) /* Busy */
+		ret &= ~1;
+	if (status & PARPORT_STATUS_ACK) /* Ack */
+		ret |= 8;
+	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+		ret |= 2;
+	if (status & PARPORT_STATUS_SELECT) /* select */
+		ret |= 4;
+	if (status & PARPORT_STATUS_ERROR) /* error */
+		ret |= 16;
+	return ret;
+}
+
+static unsigned char status_mfc3_to_pc(unsigned char status)
+{
+	unsigned char ret = PARPORT_STATUS_BUSY;
+
+	if (status & 1) /* Busy */
+		ret &= ~PARPORT_STATUS_BUSY;
+	if (status & 2) /* PaperOut */
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (status & 4) /* Selected */
+		ret |= PARPORT_STATUS_SELECT;
+	if (status & 8) /* Ack */
+		ret |= PARPORT_STATUS_ACK;
+	if (status & 16) /* /ERROR */
+		ret |= PARPORT_STATUS_ERROR;
+
+	return ret;
+}
+
+static void mfc3_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+	pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
+}
+
+static unsigned char mfc3_read_status(struct parport *p)
+{
+	unsigned char status;
+
+	status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
+DPRINTK("read_status %02x\n", status);
+	return status;
+}
+
+static void mfc3_change_mode( struct parport *p, int m)
+{
+	/* XXX: This port only has one mode, and I am
+	not sure about the corresponding PC-style mode*/
+}
+
+static int use_cnt = 0;
+
+static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i;
+
+	for( i = 0; i < MAX_MFC; i++)
+		if (this_port[i] != NULL)
+			if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+				dummy = pia(this_port[i])->pprb; /* clear irq bit */
+				parport_generic_irq(irq, this_port[i], regs);
+			}
+}
+
+static void mfc3_release_resources(struct parport *p)
+{
+DPRINTK("realease_resources\n");
+	if (p->irq != PARPORT_IRQ_NONE) 
+		if (--use_cnt == 0) 
+			free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
+}
+
+static int mfc3_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+	if (p->irq != PARPORT_IRQ_NONE)
+		if (use_cnt++ == 0)
+			if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
+				 return use_cnt--;
+	return 0;
+}
+
+static void mfc3_init_state(struct parport_state *s)
+{
+	s->u.amiga.data = 0;
+	s->u.amiga.datadir = 255;
+	s->u.amiga.status = 0;
+	s->u.amiga.statusdir = 0xe0;
+}
+
+static void mfc3_save_state(struct parport *p, struct parport_state *s)
+{
+	s->u.amiga.data = pia(p)->pprb;
+	pia(p)->crb &= ~PIA_DDR;
+	s->u.amiga.datadir = pia(p)->pddrb;
+	pia(p)->crb |= PIA_DDR;
+	s->u.amiga.status = pia(p)->ppra;
+	pia(p)->cra &= ~PIA_DDR;
+	s->u.amiga.statusdir = pia(p)->pddrb;
+	pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_restore_state(struct parport *p, struct parport_state *s)
+{
+	pia(p)->pprb = s->u.amiga.data;
+	pia(p)->crb &= ~PIA_DDR;
+	pia(p)->pddrb = s->u.amiga.datadir;
+	pia(p)->crb |= PIA_DDR;
+	pia(p)->ppra = s->u.amiga.status;
+	pia(p)->cra &= ~PIA_DDR;
+	pia(p)->pddrb = s->u.amiga.statusdir;
+	pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_enable_irq(struct parport *p)
+{
+	pia(p)->crb |= PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_disable_irq(struct parport *p)
+{
+	pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void mfc3_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static void mfc3_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_mfc3_ops = {
+	mfc3_write_data,
+	mfc3_read_data,
+
+	mfc3_write_control,
+	mfc3_read_control,
+	mfc3_frob_control,
+
+	NULL, /* write_econtrol */
+	NULL, /* read_econtrol */
+	NULL, /* frob_econtrol */
+
+	mfc3_write_status,
+	mfc3_read_status,
+
+	NULL, /* write fifo */
+	NULL, /* read fifo */
+
+	mfc3_change_mode,
+
+
+	mfc3_release_resources,
+	mfc3_claim_resources,
+
+
+	NULL, /* epp_write_data */
+	NULL, /* epp_read_data */
+	NULL, /* epp_write_addr */
+	NULL, /* epp_read_addr */
+	NULL, /* epp_check_timeout */
+
+	NULL, /* epp_write_block */
+	NULL, /* epp_read_block */
+
+	NULL, /* ecp_write_block */
+	NULL, /* ecp_read_block */
+
+	mfc3_init_state,
+	mfc3_save_state,
+	mfc3_restore_state,
+
+	mfc3_enable_irq,
+	mfc3_disable_irq,
+	mfc3_interrupt,
+
+	mfc3_inc_use_count,
+	mfc3_dec_use_count,
+	mfc3_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_mfc3_init(void))
+{
+	struct parport *p;
+	int pias = 0;
+	struct pia *pp;
+	unsigned int key = 0;
+	const struct ConfigDev *cd;
+
+	if (MACH_IS_AMIGA) {
+		while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
+			cd = zorro_get_board(key);
+			pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
+			if (pias < MAX_MFC) {
+				pp->crb = 0;
+				pp->pddrb = 255; /* all data pins output */
+				pp->crb = PIA_DDR|32|8;
+				dummy = pp->pddrb; /* reading clears interrupt */
+				pp->cra = 0;
+				pp->pddra = 0xe0; /* /RESET,  /DIR ,/AUTO-FEED output */
+				pp->cra = PIA_DDR;
+				pp->ppra = 0; /* reset printer */
+				udelay(10);
+				pp->ppra = 128;
+				if ((p = parport_register_port((unsigned long)pp,
+					IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
+					&pp_mfc3_ops))) {
+					this_port[pias++] = p;
+					printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
+					/* XXX: set operating mode */
+					parport_proc_register(p);
+					p->flags |= PARPORT_FLAG_COMA;
+					if (parport_probe_hook)
+						(*parport_probe_hook)(p);
+					zorro_config_board(key, 0);
+					p->private_data = (void *)key;
+				}
+			}
+		}
+	}
+	return pias;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
+MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+
+int init_module(void)
+{
+	return ! parport_mfc3_init();
+}
+
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_MFC; i++)
+		if (this_port[i] != NULL) {
+			if (!(this_port[i]->flags & PARPORT_FLAG_COMA))
+				parport_quiesce(this_port[i]);
+			parport_proc_unregister(this_port[i]);
+			parport_unregister_port(this_port[i]);
+			zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
+		}
+}
+#endif
+
+
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.2.7/linux/drivers/misc/parport_pc.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/misc/parport_pc.c	Mon May 10 10:26:31 1999
@@ -53,6 +53,8 @@
X    than PARPORT_MAX (in <linux/parport.h>).  */
X #define PARPORT_PC_MAX_PORTS  8
X 
+static int user_specified = 0;
+
X static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
X {
X 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
@@ -103,19 +105,24 @@
X 
X void parport_pc_write_control(struct parport *p, unsigned char d)
X {
+	struct parport_pc_private *priv = p->private_data;
+	priv->ctr = d;/* update soft copy */
X 	outb(d, p->base+CONTROL);
X }
X 
X unsigned char parport_pc_read_control(struct parport *p)
X {
-	return inb(p->base+CONTROL);
+	struct parport_pc_private *priv = p->private_data;
+	return priv->ctr;
X }
X 
X unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
X {
-	unsigned char old = inb(p->base+CONTROL);
-	outb(((old & ~mask) ^ val), p->base+CONTROL);
-	return old;
+	struct parport_pc_private *priv = p->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	outb (ctr, p->base+CONTROL);
+	return priv->ctr = ctr; /* update soft copy */
X }
X 
X void parport_pc_write_status(struct parport *p, unsigned char d)
@@ -345,6 +352,8 @@
X  */
X static int parport_SPP_supported(struct parport *pb)
X {
+	unsigned char r, w;
+
X 	/*
X 	 * first clear an eventually pending EPP timeout 
X 	 * I (sai...@ife.ee.ethz.ch) have an SMSC chipset
@@ -354,14 +363,54 @@
X 	parport_pc_epp_clear_timeout(pb);
X 
X 	/* Do a simple read-write test to make sure the port exists. */
-	parport_pc_write_control(pb, 0xc);
-	parport_pc_write_data(pb, 0xaa);
-	if (parport_pc_read_data(pb) != 0xaa) return 0;
-	
-	parport_pc_write_data(pb, 0x55);
-	if (parport_pc_read_data(pb) != 0x55) return 0;
+	w = 0xc;
+	parport_pc_write_control(pb, w);
+
+	/* Can we read from the control register?  Some ports don't
+	 * allow reads, so read_control just returns a software
+	 * copy. Some ports _do_ allow reads, so bypass the software
+	 * copy here.  In addition, some bits aren't writable. */
+	r = inb (pb->base+CONTROL);
+	if ((r & 0x3f) == w) {
+		w = 0xe;
+		parport_pc_write_control (pb, w);
+		r = inb (pb->base+CONTROL);
+		parport_pc_write_control (pb, 0xc);
+		if ((r & 0x3f) == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* That didn't work, but the user thinks there's a
+		 * port here. */
+		printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* Try the data register.  The data lines aren't tri-stated at
+	 * this stage, so we expect back what we wrote. */
+	w = 0xaa;
+	parport_pc_write_data (pb, w);
+	r = parport_pc_read_data (pb);
+	if (r == w) {
+		w = 0x55;
+		parport_pc_write_data (pb, w);
+		r = parport_pc_read_data (pb);
+		if (r == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* Didn't work with 0xaa, but the user is convinced
+		 * this is the place. */
+		printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* It's possible that we can't read the control register or
+	   the data register.  In that case just believe the user. */
+	if (user_specified)
+		return PARPORT_MODE_PCSPP;
X 
-	return PARPORT_MODE_PCSPP;
+	return 0;
X }
X 
X /* Check for ECP
@@ -712,6 +761,15 @@
X 	if (check_region(base, 3)) return 0;
X 	if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
X 		return 0;
+	p->private_data = kmalloc (sizeof (struct parport_pc_private),
+				   GFP_KERNEL);
+	if (!p->private_data) {
+		/* Not enough memory. */
+		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+		parport_unregister_port (p);
+		return 0;
+	}
+	((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
X 	if (p->base != 0x3bc) {
X 		if (!check_region(base+0x400,3)) {
X 			p->modes |= parport_ECR_present(p);	
@@ -725,6 +783,7 @@
X 	}
X 	if (!parport_SPP_supported(p)) {
X 		/* No port. */
+		kfree (p->private_data);
X 		parport_unregister_port (p);
X 		return 0;
X 	}
@@ -787,6 +846,7 @@
X 	int count = 0, i = 0;
X 	if (io && *io) {
X 		/* Only probe the ports we were given. */
+		user_specified = 1;
X 		do {
X 			count += probe_one_port(*(io++), *(irq++), *(dma++));
X 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
@@ -829,6 +889,7 @@
X 			if (!(p->flags & PARPORT_FLAG_COMA)) 
X 				parport_quiesce(p);
X 			parport_proc_unregister(p);
+			kfree (p->private_data);
X 			parport_unregister_port(p);
X 		}
X 		p = tmp;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.2.7/linux/drivers/net/3c507.c	Thu Feb 12 20:56:07 1998
+++ linux/drivers/net/3c507.c	Thu May  6 23:14:36 1999
@@ -40,6 +40,7 @@
X 	info that the casual reader might think that it documents the i82586 :-<.
X */
X 
+#include <linux/config.h>
X #include <linux/kernel.h>
X #include <linux/sched.h>
X #include <linux/types.h>
@@ -53,6 +54,7 @@
X #include <asm/bitops.h>
X #include <asm/io.h>
X #include <asm/dma.h>
+#include <asm/spinlock.h>
X #include <linux/errno.h>
X 
X #include <linux/netdevice.h>
@@ -123,6 +125,7 @@
X 	ushort tx_head;
X 	ushort tx_cmd_link;
X 	ushort tx_reap;
+	spinlock_t lock;
X };
X 
X /*
@@ -448,6 +451,7 @@
X 	struct net_local *lp = (struct net_local *)dev->priv;
X 	int ioaddr = dev->base_addr;
X 	unsigned long shmem = dev->mem_start;
+	unsigned long flags;
X 
X 	if (dev->tbusy) 
X 	{
@@ -487,7 +491,13 @@
X 		lp->stats.tx_bytes+=length;
X 		/* Disable the 82586's input to the interrupt line. */
X 		outb(0x80, ioaddr + MISC_CTRL);
+#ifdef CONFIG_SMP
+		spin_lock_irqsave(&lp->lock, flags);
X 		hardware_send_packet(dev, buf, length);
+		spin_unlock_irqrestore(&lp->lock, flags);
+#else
+		hardware_send_packet(dev, buf, length);
+#endif		
X 		dev->trans_start = jiffies;
X 		/* Enable the 82586 interrupt input. */
X 		outb(0x84, ioaddr + MISC_CTRL);
@@ -515,11 +525,14 @@
X 		return;
X 	}
X 	dev->interrupt = 1;
+	
X 
X 	ioaddr = dev->base_addr;
X 	lp = (struct net_local *)dev->priv;
X 	shmem = dev->mem_start;
X 
+	spin_lock(&lp->lock);
+
X 	status = readw(shmem+iSCB_STATUS);
X 
X 	if (net_debug > 4) {
@@ -598,6 +611,7 @@
X 
X 	/* Enable the 82586's interrupt input. */
X 	outb(0x84, ioaddr + MISC_CTRL);
+	spin_unlock(&lp->lock);
X 
X 	return;
X }
diff -u --recursive --new-file v2.2.7/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.2.7/linux/drivers/net/3c509.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/net/3c509.c	Thu May  6 14:02:34 1999
@@ -568,7 +568,7 @@
X 		 */
X 
X #ifdef __SMP__
-		disable_irq(dev->irq);
+		disable_irq_nosync(dev->irq);
X 	    	spin_lock(&lp->lock);
X #endif	    	
X 	    
diff -u --recursive --new-file v2.2.7/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.2.7/linux/drivers/net/8390.c	Wed Mar 10 15:29:46 1999
+++ linux/drivers/net/8390.c	Thu May  6 14:02:34 1999
@@ -257,8 +257,7 @@
X 
X 		/* Ugly but a reset can be slow, yet must be protected */
X 		
-		disable_irq(dev->irq);
-		synchronize_irq();
+		disable_irq_nosync(dev->irq);
X 		spin_lock(&ei_local->page_lock);
X 		
X 		/* Try to restart the card.  Perhaps the user has fixed something. */
@@ -286,8 +285,7 @@
X 	 *	Slow phase with lock held.
X 	 */
X 	 
-	disable_irq(dev->irq);
-	synchronize_irq();
+	disable_irq_nosync(dev->irq);
X 	
X 	spin_lock(&ei_local->page_lock);
X 	
diff -u --recursive --new-file v2.2.7/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.2.7/linux/drivers/net/de4x5.c	Thu Dec 31 10:29:00 1998
+++ linux/drivers/net/de4x5.c	Sat May  8 19:46:44 1999
@@ -225,11 +225,18 @@
X     to  determine this in  advance other than by  trial and error and common
X     sense, e.g. call a BNC connectored port 'BNC', not '10Mb'.
X 
-    TO DO:
-    ------
+    Changed the bus probing.  EISA used to be  done first,  followed by PCI.
+    Most people probably don't even know  what a de425 is today and the EISA
+    probe has messed  up some SCSI cards  in the past,  so now PCI is always
+    probed  first  followed by  EISA if  a) the architecture allows EISA and
+    either  b) there have been no PCI cards detected or  c) an EISA probe is
+    forced by  the user.  To force  a probe  include  "force_eisa"  in  your
+    insmod "args" line;  for built-in kernels either change the driver to do
+    this  automatically  or include  #define DE4X5_FORCE_EISA  on or  before
+    line 1040 in the driver.
X 
-    o check what revision numbers the 21142 and 21143 have
-    o
+    TO DO: 
+    ------
X 
X     Revision History
X     ----------------
@@ -416,11 +423,14 @@
X 			   access traps. This flag is merely for log messages:
X 			   should do something more definitive though...
X       0.543  30-Dec-98    Add SMP spin locking.
-
+      0.544   8-May-99    Fix for buggy SROM in Motorola embedded boards using
+                           a 21143 by <mmpo...@home.com>.
+			  Change PCI/EISA bus probing order.
+ 
X     =========================================================================
X */
X 
-static const char *version = "de4x5.c:V0.543 1998/12/30 dav...@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.544 1999/5/8 dav...@maniac.ultranet.com\n";
X 
X #include <linux/config.h>
X #include <linux/module.h>
@@ -1027,8 +1037,11 @@
X #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
X static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
X static int lastEISA = 0;
-#else
-static int lastEISA = MAX_EISA_SLOTS;           /* Only PCI probes */
+#  ifdef DE4X5_FORCE_EISA                 /* Force an EISA bus probe or not */
+static int forceEISA = 1;
+#  else
+static int forceEISA = 0;
+#  endif
X #endif
X static int num_de4x5s = 0;
X static int cfrv = 0, useSROM = 0;
@@ -1098,12 +1111,12 @@
X {
X     u_long iobase = dev->base_addr;
X 
+    pci_probe(dev, iobase);
X #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-    eisa_probe(dev, iobase);
-#endif
-    if (lastEISA == MAX_EISA_SLOTS) {
-	pci_probe(dev, iobase);
+    if ((lastPCI == NO_MORE_PCI) && ((num_de4x5s == 0) || forceEISA)) {
+        eisa_probe(dev, iobase);
X     }
+#endif
X     
X     return (dev->priv ? 0 : -ENODEV);
X }
@@ -1230,6 +1243,7 @@
X 	if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
X 				   GFP_KERNEL)) == NULL) {
X 	    kfree(lp->cache.priv);
+	    lp->cache.priv = NULL;
X 	    return -ENOMEM;
X 	}
X 
@@ -2066,38 +2080,36 @@
X     }
X     
X     for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
-	if (EISA_signature(name, EISA_ID)) {
-	    cfid = (u32) inl(PCI_CFID);
-	    cfrv = (u_short) inl(PCI_CFRV);
-	    device = (cfid >> 8) & 0x00ffff00;
-	    vendor = (u_short) cfid;
+	if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE)) continue;
+	if (!EISA_signature(name, EISA_ID)) continue;
+
+	cfid = (u32) inl(PCI_CFID);
+	cfrv = (u_short) inl(PCI_CFRV);
+	device = (cfid >> 8) & 0x00ffff00;
+	vendor = (u_short) cfid;
X 	    
-	    /* Read the EISA Configuration Registers */
-	    irq = inb(EISA_REG0);
-	    irq = de4x5_irq[(irq >> 1) & 0x03];
-
-	    if (is_DC2114x) {
-		device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
-	    }
-	    lp->chipset = device;
-
-	    /* Write the PCI Configuration Registers */
-	    outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
-	    outl(0x00006000, PCI_CFLT);
-	    outl(iobase, PCI_CBIO);
+	/* Read the EISA Configuration Registers */
+	irq = inb(EISA_REG0);
+	irq = de4x5_irq[(irq >> 1) & 0x03];
+
+	if (is_DC2114x) {
+	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+	}
+	lp->chipset = device;
+
+	/* Write the PCI Configuration Registers */
+	outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
+	outl(0x00006000, PCI_CFLT);
+	outl(iobase, PCI_CBIO);
X 	    
-	    DevicePresent(EISA_APROM);
-	    if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
-		dev->irq = irq;
-		if ((status = de4x5_hw_init(dev, iobase)) == 0) {
-		    num_de4x5s++;
-		    if (loading_module) link_modules(lastModule, dev);
-		    lastEISA = i;
-		    return;
-		}
-	    } else if (ioaddr != 0) {
-		printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
-	    }
+	DevicePresent(EISA_APROM);
+
+	dev->irq = irq;
+	if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+	    num_de4x5s++;
+	    if (loading_module) link_modules(lastModule, dev);
+	    lastEISA = i;
+	    return;
X 	}
X     }
X 
@@ -4794,6 +4806,7 @@
X     if (lp->state == INITIALISED) {
X         lp->ibn = 3;
X         lp->active = *p++;
+	if (MOTO_SROM_BUG) lp->active = 0;
X 	lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
X 	lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
X 	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
@@ -5326,6 +5339,9 @@
X 	t = *q;
X 	*q = '\0';
X 
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+	if (strstr(p, "force_eisa") || strstr(p, "FORCE_EISA")) forceEISA = 1;
+#endif
X 	if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
X 
X 	if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
@@ -5766,6 +5782,12 @@
X 		release_region(p->base_addr, (lp->bus == PCI ? 
X 					      DE4X5_PCI_TOTAL_SIZE :
X 					      DE4X5_EISA_TOTAL_SIZE));
+		if (lp->cache.buf) {        /* MAC buffers allocated?    */
+		    kfree(lp->cache.buf);   /* Free the MAC buffers      */
+		}
+		if (lp->cache.priv) {       /* Private area allocated?   */
+		    kfree(lp->cache.priv);  /* Free the private area     */
+		}
X 	    }
X 	    kfree(p);
X 	} else {
@@ -5799,10 +5821,10 @@
X 	if (lp->cache.buf) {                /* MAC buffers allocated?    */
X 	    kfree(lp->cache.buf);           /* Free the MAC buffers      */
X 	}
-	kfree(lp->cache.priv);              /* Free the private area     */
X 	release_region(p->base_addr, (lp->bus == PCI ? 
X 				      DE4X5_PCI_TOTAL_SIZE :
X 				      DE4X5_EISA_TOTAL_SIZE));
+	kfree(lp->cache.priv);              /* Free the private area     */
X     }
X     unregister_netdev(p);
X     kfree(p);                               /* Free the device structure */
@@ -5867,6 +5889,9 @@
X  * Local variables:
X  *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
X  *
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
+ * Delete -D__SMP__ below if you didn't define this in your kernel
+ * Delete -DMODVERSIONS below if you didn't define this in your kernel
+ *
+ *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
X  * End:
X  */
diff -u --recursive --new-file v2.2.7/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.2.7/linux/drivers/net/de4x5.h	Thu Dec 31 10:29:00 1998
+++ linux/drivers/net/de4x5.h	Tue May 11 08:34:32 1999
@@ -1027,3 +1027,5 @@
X #define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
X 
X #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
diff -u --recursive --new-file v2.2.7/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.2.7/linux/drivers/net/eexpress.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/net/eexpress.c	Thu May  6 23:14:36 1999
@@ -83,6 +83,7 @@
X  * practice.
X  */
X   
+#include <linux/config.h>
X #include <linux/module.h>
X 
X #include <linux/kernel.h>
@@ -107,6 +108,8 @@
X #include <linux/skbuff.h>
X #include <linux/malloc.h>
X 
+#include <asm/spinlock.h>
+
X #ifndef NET_DEBUG
X #define NET_DEBUG 4
X #endif
@@ -141,6 +144,7 @@
X 	unsigned char width;         /* 0 for 16bit, 1 for 8bit */
X 	unsigned char was_promisc;
X 	unsigned char old_mc_count;
+	spinlock_t lock;
X };
X 
X /* This is the code and data that is downloaded to the EtherExpress card's
@@ -502,6 +506,7 @@
X static int eexp_xmit(struct sk_buff *buf, struct device *dev)
X {
X 	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
X 
X #if NET_DEBUG > 6
X 	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
@@ -509,6 +514,15 @@
X 
X 	disable_irq(dev->irq);
X 
+	/*
+	 *	Best would be to use synchronize_irq(); spin_lock() here
+	 *	lets make it work first..
+	 */
+	 
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&lp->lock, flags);
+#endif
+
X 	/* If dev->tbusy is set, all our tx buffers are full but the kernel
X 	 * is calling us anyway.  Check that nothing bad is happening.
X 	 */
@@ -516,7 +530,13 @@
X 		int status = scb_status(dev);
X   		unstick_cu(dev);
X 		if ((jiffies - lp->last_tx) < HZ)
+		{
+#ifdef CONFIG_SMP
+			spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+
X 			return 1;
+		}
X 		printk(KERN_INFO "%s: transmit timed out, %s?", dev->name,
X 		       (SCB_complete(status)?"lost interrupt":
X 			"board on fire"));
@@ -544,6 +564,9 @@
X 	        eexp_hw_tx_pio(dev,data,length);
X 	}
X 	dev_kfree_skb(buf);
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&lp->lock, flags);
+#endif
X 	enable_irq(dev->irq);
X 	return 0;
X }
@@ -646,11 +669,14 @@
X 	lp = (struct net_local *)dev->priv;
X 	ioaddr = dev->base_addr;
X 
+	spin_lock(&lp->lock);
+
X 	old_read_ptr = inw(ioaddr+READ_PTR);
X 	old_write_ptr = inw(ioaddr+WRITE_PTR);
X 
X 	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
X 
+	
X 	dev->interrupt = 1;
X 
X 	status = scb_status(dev);
@@ -726,6 +752,8 @@
X #endif
X 	outw(old_read_ptr, ioaddr+READ_PTR);
X 	outw(old_write_ptr, ioaddr+WRITE_PTR);
+	
+	spin_unlock(&lp->lock);
X 	return;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.2.7/linux/drivers/net/epic100.c	Wed Jan 13 15:00:42 1999
+++ linux/drivers/net/epic100.c	Thu Apr 29 11:53:41 1999
@@ -1106,6 +1106,7 @@
X 				memcpy(skb_put(skb, pkt_len),
X 					   bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len);
X #endif
+				ep->rx_ring[entry].status = 0x8000;
X 			} else {
X 				skb_put(skb = ep->rx_skbuff[entry], pkt_len);
X 				ep->rx_skbuff[entry] = NULL;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.2.7/linux/drivers/net/eql.c	Thu May  7 22:51:50 1998
+++ linux/drivers/net/eql.c	Mon May 10 13:00:10 1999
@@ -363,8 +363,8 @@
X 
X 	eql_schedule_slaves (eql->queue);
X   
-	slave_dev = eql_best_slave_dev (eql->queue);
X 	slave = eql_best_slave (eql->queue); 
+	slave_dev = slave ? slave->dev : 0;
X 
X 	if ( slave_dev != 0 )
X 	{
diff -u --recursive --new-file v2.2.7/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- v2.2.7/linux/drivers/net/ethertap.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/ethertap.c	Tue May 11 08:24:31 1999
@@ -177,11 +177,21 @@
X #endif
X 
X 	if (skb_headroom(skb) < 2) {
-		printk(KERN_DEBUG "%s : bug --- xmit with head<2\n", dev->name);
+		static int once;
+	  	struct sk_buff *skb2;
+
+		if (!once) {
+			once = 1;
+			printk(KERN_DEBUG "%s: not aligned xmit by protocol %04x\n", dev->name, skb->protocol);
+		}
+
+		skb2 = skb_realloc_headroom(skb, 2);
X 		dev_kfree_skb(skb);
-		return 0;
+		if (skb2 == NULL)
+			return 0;
+		skb = skb2;
X 	}
-	skb_push(skb, 2);
+	__skb_push(skb, 2);
X 
X 	/* Make the same thing, which loopback does. */
X 	if (skb_shared(skb)) {
diff -u --recursive --new-file v2.2.7/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.2.7/linux/drivers/net/ibmtr.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/ibmtr.c	Fri May  7 10:57:42 1999
@@ -513,6 +513,7 @@
X 	/* How much shared RAM is on adapter ? */
X #ifdef PCMCIA
X 	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
+	ibmtr_mem_base = ti->sram_base ; 
X #else
X 	ti->avail_shared_ram = get_sram_size(ti);
X #endif
@@ -1498,6 +1499,7 @@
X 	       ti->asb + offsetof(struct asb_rec, rec_buf_addr));
X 
X 	lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len));
+	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
X 	
X 	llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
X 
@@ -1524,8 +1526,10 @@
X 		return;
X 	}
X 
+	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
X        	if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) &&
-       	    (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP)) {
+       	    (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) &&
+		(length>=hdr_len)) {
X        		IPv4_p = 1;
X        	}
X 
@@ -1556,7 +1560,6 @@
X        	}
X #endif
X 
-       	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
X        	skb_size = length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc);
X  
X        	if (!(skb=dev_alloc_skb(skb_size))) {
@@ -1576,7 +1579,6 @@
X 
X 	if (IPv4_p) {
X                 /* Copy the headers without checksumming */
-		hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
X 		memcpy_fromio(data, rbufdata, hdr_len);
X 
X 		/* Watch for padded packets and bogons */
diff -u --recursive --new-file v2.2.7/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.2.7/linux/drivers/net/ppp.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/ppp.c	Tue May 11 09:55:45 1999
@@ -4,7 +4,7 @@
X  *  Al Longyear <long...@netcom.com>
X  *  Extensively rewritten by Paul Mackerras <pau...@cs.anu.edu.au>
X  *
- *  ==FILEVERSION 990331==
+ *  ==FILEVERSION 990510==
X  *
X  *  NOTE TO MAINTAINERS:
X  *     If you modify this file at all, please set the number above to the
@@ -90,9 +90,6 @@
X #include <linux/kmod.h>
X #endif
X 
-typedef ssize_t		rw_ret_t;
-typedef size_t		rw_count_t;
-
X /*
X  * Local functions
X  */
@@ -109,6 +106,7 @@
X static int ppp_async_encode(struct ppp *ppp);
X static int ppp_async_send(struct ppp *, struct sk_buff *);
X static int ppp_sync_send(struct ppp *, struct sk_buff *);
+static void ppp_tty_flush_output(struct ppp *);
X 
X static int ppp_ioctl(struct ppp *, unsigned int, unsigned long);
X static int ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp);
@@ -191,10 +189,10 @@
X  * TTY callbacks
X  */
X 
-static rw_ret_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
-			     rw_count_t);
-static rw_ret_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
-			      rw_count_t);
+static ssize_t ppp_tty_read(struct tty_struct *, struct file *, __u8 *,
+			    size_t);
+static ssize_t ppp_tty_write(struct tty_struct *, struct file *, const __u8 *,
+			     size_t);
X static int ppp_tty_ioctl(struct tty_struct *, struct file *, unsigned int,
X 			 unsigned long);
X static unsigned int ppp_tty_poll(struct tty_struct *tty, struct file *filp,
@@ -241,6 +239,7 @@
X 	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
X 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
X };
+EXPORT_SYMBOL(ppp_crc16_table);
X 
X #ifdef CHECK_CHARACTERS
X static __u32 paritytab[8] =
@@ -445,6 +444,7 @@
X 		ppp->tty = ppp->backup_tty;
X 		if (ppp_tty_push(ppp))
X 			ppp_output_wakeup(ppp);
+		wake_up_interruptible(&ppp->read_wait);
X 	} else {
X 		ppp->tty = 0;
X 		ppp->sc_xfer = 0;
@@ -462,13 +462,13 @@
X  * Read a PPP frame from the rcv_q list,
X  * waiting if necessary
X  */
-static rw_ret_t
+static ssize_t
X ppp_tty_read(struct tty_struct *tty, struct file *file, __u8 * buf,
-	     rw_count_t nr)
+	     size_t nr)
X {
X 	struct ppp *ppp = tty2ppp (tty);
X 	struct sk_buff *skb;
-	rw_ret_t len, err;
+	ssize_t len, err;
X 
X 	/*
X 	 * Validate the pointers
@@ -550,9 +550,9 @@
X  * Writing to a tty in ppp line discipline sends a PPP frame.
X  * Used by pppd to send control packets (LCP, etc.).
X  */
-static rw_ret_t
+static ssize_t
X ppp_tty_write(struct tty_struct *tty, struct file *file, const __u8 * data,
-	      rw_count_t count)
+	      size_t count)
X {
X 	struct ppp *ppp = tty2ppp (tty);
X 	__u8 *new_data;
@@ -604,7 +604,7 @@
X 	 */
X 	ppp_send_ctrl(ppp, skb);
X 
-	return (rw_ret_t) count;
+	return (ssize_t) count;
X }
X 
X /*
@@ -723,6 +723,21 @@
X 		error = n_tty_ioctl (tty, file, param2, param3);
X 		break;
X 
+	case TCFLSH:
+		/*
+		 * Flush our buffers, then call the generic code to
+		 * flush the serial port's buffer.
+		 */
+		if (param3 == TCIFLUSH || param3 == TCIOFLUSH) {
+			struct sk_buff *skb;
+			while ((skb = skb_dequeue(&ppp->rcv_q)) != NULL)
+				kfree_skb(skb);
+		}
+		if (param3 == TCIOFLUSH || param3 == TCOFLUSH)
+			ppp_tty_flush_output(ppp);
+		error = n_tty_ioctl (tty, file, param2, param3);
+		break;
+
X 	case FIONREAD:
X 		/*
X 		 * Returns how many bytes are available for a read().
@@ -881,7 +896,7 @@
X 	save_flags(flags);
X 	cli();
X 	if (ppp->tty_pushing) {
-		/* record wakeup attempt so we don't loose */
+		/* record wakeup attempt so we don't lose */
X 		/* a wakeup call while doing push processing */
X 		ppp->woke_up=1;
X 		restore_flags(flags);
@@ -964,16 +979,20 @@
X 	int avail, sent, done = 0;
X 	struct tty_struct *tty = ppp2tty(ppp);
X 	
-	if ( ppp->flags & SC_SYNC ) 
+	if (ppp->flags & SC_SYNC) 
X 		return ppp_tty_sync_push(ppp);
X 
X 	CHECK_PPP(0);
-	if (ppp->tty_pushing)
+	if (ppp->tty_pushing) {
+		ppp->woke_up = 1;
X 		return 0;
+	}
X 	if (tty == NULL || tty->disc_data != (void *) ppp)
X 		goto flush;
X 	while (ppp->optr < ppp->olim || ppp->tpkt != 0) {
X 		ppp->tty_pushing = 1;
+		mb();
+		ppp->woke_up = 0;
X 		avail = ppp->olim - ppp->optr;
X 		if (avail > 0) {
X 			tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
@@ -983,18 +1002,24 @@
X 			ppp->stats.ppp_obytes += sent;
X 			ppp->optr += sent;
X 			if (sent < avail) {
+				wmb();
X 				ppp->tty_pushing = 0;
+				mb();
+				if (ppp->woke_up)
+					continue;
X 				return done;
X 			}
X 		}
X 		if (ppp->tpkt != 0)
X 			done = ppp_async_encode(ppp);
+		wmb();
X 		ppp->tty_pushing = 0;
X 	}
X 	return done;
X 
X flush:
X 	ppp->tty_pushing = 1;
+	mb();
X 	ppp->stats.ppp_oerrors++;
X 	if (ppp->tpkt != 0) {
X 		kfree_skb(ppp->tpkt);
@@ -1002,6 +1027,7 @@
X 		done = 1;
X 	}
X 	ppp->optr = ppp->olim;
+	wmb();
X 	ppp->tty_pushing = 0;
X 	return done;
X }
@@ -1113,6 +1139,32 @@
X 	ppp->tpkt_pos = i;
X 	ppp->tfcs = fcs;
X 	return 0;
+}
+
+/*
+ * Flush output from our internal buffers.
+ * Called for the TCFLSH ioctl.
+ */
+static void
+ppp_tty_flush_output(struct ppp *ppp)
+{
+	struct sk_buff *skb;
+	int done = 0;
+
+	while ((skb = skb_dequeue(&ppp->xmt_q)) != NULL)
+		kfree_skb(skb);
+	ppp->tty_pushing = 1;
+	mb();
+	ppp->optr = ppp->olim;
+	if (ppp->tpkt != NULL) {
+		kfree_skb(ppp->tpkt);
+		ppp->tpkt = 0;
+		done = 1;
+	}
+	wmb();
+	ppp->tty_pushing = 0;
+	if (done)
+		ppp_output_wakeup(ppp);
X }
X 
X /*
diff -u --recursive --new-file v2.2.7/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.2.7/linux/drivers/net/via-rhine.c	Mon Dec 28 15:00:52 1998
+++ linux/drivers/net/via-rhine.c	Mon May 10 13:00:10 1999
@@ -456,9 +456,9 @@
X 				   pci_tbl[chip_idx].name, pciaddr, irq);
X 
X 		if (pci_tbl[chip_idx].flags & PCI_USES_IO) {
-			if (check_region(pciaddr, pci_tbl[chip_idx].io_size))
-				continue;
X 			ioaddr = pciaddr & ~3;
+			if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
+				continue;
X 		} else if ((ioaddr = (long)ioremap(pciaddr & ~0xf,
X 										 pci_tbl[chip_idx].io_size)) == 0) {
X 			printk(KERN_INFO "Failed to map PCI address %#lx.\n",
@@ -1053,6 +1053,7 @@
X 			skb->protocol = eth_type_trans(skb, dev);
X 			netif_rx(skb);
X 			dev->last_rx = jiffies;
+			np->stats.rx_bytes += pkt_len;
X 			np->stats.rx_packets++;
X 		}
X 		entry = (++np->cur_rx) % RX_RING_SIZE;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.2.7/linux/drivers/net/wavelan.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/net/wavelan.c	Thu Apr 29 11:53:41 1999
@@ -324,6 +324,7 @@
X 
X   return crc_bytes;
X } /* psa_crc */
+#endif	/* SET_PSA_CRC */
X 
X /*------------------------------------------------------------------*/
X /*
@@ -334,6 +335,7 @@
X 		    u_long	ioaddr,
X 		    u_short	hacr)
X {
+#ifdef SET_PSA_CRC
X   psa_t		psa;
X   u_short	crc;
X 
@@ -363,8 +365,8 @@
X   if(crc != 0)
X     printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
X #endif /* DEBUG_IOCTL_INFO */
-} /* update_psa_checksum */
X #endif	/* SET_PSA_CRC */
+} /* update_psa_checksum */
X 
X /*------------------------------------------------------------------*/
X /*
@@ -748,23 +750,23 @@
X       unsigned short	ias_addr;
X 
X       /* Check mc_config command */
-      if((status & AC_SFLD_OK) != 0)
-	printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
-	       dev->name, str, status);
+      if((status & AC_SFLD_OK) != AC_SFLD_OK)
+	printk(KERN_INFO "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
+	       dev->name, status);
X 
X       /* check ia-config command */
X       ias_addr = mcs_addr - sizeof(ac_ias_t);
X       obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status));
-      if((status & AC_SFLD_OK) != 0)
-	printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
-	       dev->name, str, status);
+      if((status & AC_SFLD_OK) != AC_SFLD_OK)
+	printk(KERN_INFO "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n",
+	       dev->name, status);
X 
X       /* Check config command. */
X       cfg_addr = ias_addr - sizeof(ac_cfg_t);
X       obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
-      if((status & AC_SFLD_OK) != 0)
-	printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n",
-	       dev->name, str, status);
+      if((status & AC_SFLD_OK) != AC_SFLD_OK)
+	printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n",
+	       dev->name, status);
X #endif	/* DEBUG_CONFIG_ERROR */
X 
X       ret = 1;		/* Ready to be scrapped */
@@ -800,15 +802,15 @@
X       /* Read the first transmit buffer */
X       obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
X 
+      /* If not completed -> exit */
+      if((tx_status & AC_SFLD_C) == 0)
+	break;
+
X       /* Hack for reconfiguration */
X       if(tx_status == 0xFFFF)
X 	if(!wv_config_complete(dev, ioaddr, lp))
X 	  break;	/* Not completed */
X 
-      /* If not completed -> exit */
-      if((tx_status & AC_SFLD_C) == 0)
-	break;
-
X       /* We now remove this buffer */
X       nreaped++;
X       --lp->tx_n_in_use;
@@ -841,7 +843,7 @@
X 	  lp->stats.tx_packets++;
X 	  ncollisions = tx_status & AC_SFLD_MAXCOL;
X 	  lp->stats.collisions += ncollisions;
-#ifdef DEBUG_INTERRUPT_INFO
+#ifdef DEBUG_TX_INFO
X 	  if(ncollisions > 0)
X 	    printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n",
X 		   dev->name, ncollisions);
@@ -850,53 +852,49 @@
X       else
X 	{
X 	  lp->stats.tx_errors++;
-#ifndef IGNORE_NORMAL_XMIT_ERRS
X 	  if(tx_status & AC_SFLD_S10)
X 	    {
X 	      lp->stats.tx_carrier_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: no CS.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n",
X 		     dev->name);
X #endif
X 	    }
-#endif	/* IGNORE_NORMAL_XMIT_ERRS */
X 	  if(tx_status & AC_SFLD_S9)
X 	    {
X 	      lp->stats.tx_carrier_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: lost CTS.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n",
X 		     dev->name);
X #endif
X 	    }
X 	  if(tx_status & AC_SFLD_S8)
X 	    {
X 	      lp->stats.tx_fifo_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: slow DMA.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n",
X 		     dev->name);
X #endif
X 	    }
-#ifndef IGNORE_NORMAL_XMIT_ERRS
X 	  if(tx_status & AC_SFLD_S6)
X 	    {
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 16'
echo 'File patch-2.2.8 is continued in part 17'
echo 17 > _shar_seq_.tmp
#!/bin/sh
# this is part 17 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 17; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 	      lp->stats.tx_heartbeat_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: heart beat.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n",
X 		     dev->name);
X #endif
X 	    }
X 	  if(tx_status & AC_SFLD_S5)
X 	    {
X 	      lp->stats.tx_aborted_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: too many collisions.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n",
X 		     dev->name);
X #endif
X 	    }
-#endif	/* IGNORE_NORMAL_XMIT_ERRS */
X 	}
X 
-#ifdef DEBUG_INTERRUPT_INFO
+#ifdef DEBUG_TX_INFO
X       printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
X 	     dev->name, tx_status);
X #endif
@@ -1323,21 +1321,21 @@
X 	       char *		msg1,		/* Name of the device */
X 	       char *		msg2)		/* Name of the function */
X {
-#ifndef DEBUG_PACKET_DUMP
+  int		i;
+  int		maxi;
+
X   printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
X 	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
X   printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
X 	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
X 
-#else	/* DEBUG_PACKET_DUMP */
-  int		i;
-  int		maxi;
+#ifdef DEBUG_PACKET_DUMP
X 
-  printk(KERN_DEBUG "%s: %s(): len=%d, data=\"", msg1, msg2, length);
+  printk(KERN_DEBUG "data=\"");
X 
X   if((maxi = length) > DEBUG_PACKET_DUMP)
X     maxi = DEBUG_PACKET_DUMP;
-  for(i = 0; i < maxi; i++)
+  for(i = 14; i < maxi; i++)
X     if(p[i] >= ' ' && p[i] <= '~')
X       printk(" %c", p[i]);
X     else
@@ -1564,7 +1562,9 @@
X /*------------------------------------------------------------------*/
X /*
X  * This function doesn't exist.
+ * (Note : it was a nice way to test the reconfigure stuff...)
X  */
+#ifdef SET_MAC_ADDRESS
X static int
X wavelan_set_mac_address(device *	dev,
X 			void *		addr)
@@ -1579,6 +1579,7 @@
X 
X   return 0;
X }
+#endif	/* SET_MAC_ADDRESS */
X 
X #ifdef WIRELESS_EXT	/* if wireless extensions exist in the kernel */
X 
@@ -1932,10 +1933,8 @@
X 	  /* Disable NWID in the mmc (no filtering). */
X 	  mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
X 	}
-#ifdef SET_PSA_CRC
X       /* update the Wavelan checksum */
X       update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
X       break;
X 
X     case SIOCGIWNWID:
@@ -1992,10 +1991,8 @@
X       psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
X       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
X 	       (unsigned char *) &psa.psa_thr_pre_set, 1);
-#ifdef SET_PSA_CRC
X       /* update the Wavelan checksum */
X       update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
X       mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
X       break;
X 
@@ -2043,10 +2040,8 @@
X 
X 	   mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
X 	 }
-#ifdef SET_PSA_CRC
X        /* update the Wavelan checksum */
X        update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
X        break;
X 
X      case SIOCGIWENCODE:
@@ -2260,10 +2255,8 @@
X       psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
X       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
X 	       (unsigned char *)&psa.psa_quality_thr, 1);
-#ifdef SET_PSA_CRC
X       /* update the Wavelan checksum */
X       update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
X       mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
X       break;
X 
@@ -2426,7 +2419,7 @@
X 
X #ifdef DEBUG_RX_TRACE
X   printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
-	 dev->name, fd_p, sksize);
+	 dev->name, buf_off, sksize);
X #endif
X 
X   /* Allocate buffer for the data */
@@ -2514,6 +2507,8 @@
X {
X   u_long	ioaddr = dev->base_addr;
X   net_local *	lp = (net_local *)dev->priv;
+  fd_t		fd;
+  rbd_t		rbd;
X   int		nreaped = 0;
X 
X #ifdef DEBUG_RX_TRACE
@@ -2523,12 +2518,17 @@
X   /* Loop on each received packet. */
X   for(;;)
X     {
-      fd_t		fd;
-      rbd_t		rbd;
-      ushort		pkt_len;
-
X       obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
X 
+      /* Note about the status :
+       * It start up to be 0 (the value we set). Then, when the RU
+       * grab the buffer to prepare for reception, it sets the
+       * FD_STATUS_B flag. When the RU has finished receiving the
+       * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate
+       * completion and set the other flags to indicate the eventual
+       * errors. FD_STATUS_OK indicates that the reception was OK.
+       */
+
X       /* If the current frame is not complete, we have reached the end. */
X       if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
X 	break;		/* This is how we exit the loop. */
@@ -2536,35 +2536,44 @@
X       nreaped++;
X 
X       /* Check whether frame was correctly received. */
-      if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) !=
-	 (FD_STATUS_B | FD_STATUS_OK))
+      if((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK)
X 	{
-	  /*
-	   * Not sure about this one -- it does not seem
-	   * to be an error so we will keep quiet about it.
-	   */
-#ifndef IGNORE_NORMAL_XMIT_ERRS
-#ifdef DEBUG_RX_ERROR
-	  if((fd.fd_status & FD_STATUS_B) != FD_STATUS_B)
-	    printk(KERN_INFO "%s: wv_receive(): frame not consumed by RU.\n",
-		   dev->name);
-#endif
-#endif	/* IGNORE_NORMAL_XMIT_ERRS */
+	  /* Does the frame contain a pointer to the data?  Let's check. */
+	  if(fd.fd_rbd_offset != I82586NULL)
+	    {
+	      /* Read the receive buffer descriptor */
+	      obram_read(ioaddr, fd.fd_rbd_offset,
+			 (unsigned char *) &rbd, sizeof(rbd));
X 
X #ifdef DEBUG_RX_ERROR
-	  if((fd.fd_status & FD_STATUS_OK) != FD_STATUS_OK)
-	    printk(KERN_INFO "%s: wv_receive(): frame not received successfully.\n",
+	      if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF)
+		printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n",
+		       dev->name);
+
+	      if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F)
+		printk(KERN_INFO "%s: wv_receive(): missing F flag.\n",
+		       dev->name);
+#endif	/* DEBUG_RX_ERROR */
+
+	      /* Read the packet and transmit to Linux */
+	      wv_packet_read(dev, rbd.rbd_bufl,
+			     rbd.rbd_status & RBD_STATUS_ACNT);
+	    }
+#ifdef DEBUG_RX_ERROR
+	  else	/* if frame has no data */
+	    printk(KERN_INFO "%s: wv_receive(): frame has no data.\n",
X 		   dev->name);
X #endif
X 	}
-
-      /* Were there problems in processing the frame?  Let's check. */
-      if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 |
-			  FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11))
-	 != 0)
+      else	/* If reception was no successful */
X 	{
X 	  lp->stats.rx_errors++;
X 
+#ifdef DEBUG_RX_INFO
+	  printk(KERN_DEBUG "%s: wv_receive(): frame not received successfully (%X).\n",
+		 dev->name, fd.fd_status);
+#endif
+
X #ifdef DEBUG_RX_ERROR
X 	  if((fd.fd_status & FD_STATUS_S6) != 0)
X 	    printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name);
@@ -2573,8 +2582,8 @@
X 	  if((fd.fd_status & FD_STATUS_S7) != 0)
X 	    {
X 	      lp->stats.rx_length_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): frame too short.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): frame too short.\n",
X 		     dev->name);
X #endif
X 	    }
@@ -2582,8 +2591,8 @@
X 	  if((fd.fd_status & FD_STATUS_S8) != 0)
X 	    {
X 	      lp->stats.rx_over_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): rx DMA overrun.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): rx DMA overrun.\n",
X 		     dev->name);
X #endif
X 	    }
@@ -2591,8 +2600,8 @@
X 	  if((fd.fd_status & FD_STATUS_S9) != 0)
X 	    {
X 	      lp->stats.rx_fifo_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): ran out of resources.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): ran out of resources.\n",
X 		     dev->name);
X #endif
X 	    }
@@ -2600,8 +2609,8 @@
X 	  if((fd.fd_status & FD_STATUS_S10) != 0)
X 	    {
X 	      lp->stats.rx_frame_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): alignment error.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): alignment error.\n",
X 		     dev->name);
X #endif
X 	    }
@@ -2609,38 +2618,12 @@
X 	  if((fd.fd_status & FD_STATUS_S11) != 0)
X 	    {
X 	      lp->stats.rx_crc_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): CRC error.\n", dev->name);
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): CRC error.\n", dev->name);
X #endif
X 	    }
X 	}
X 
-      /* Does the frame contain a pointer to the data?  Let's check. */
-      if(fd.fd_rbd_offset == I82586NULL)
-#ifdef DEBUG_RX_ERROR
-	printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name);
-#endif
-      else
-	{
-	  obram_read(ioaddr, fd.fd_rbd_offset,
-		     (unsigned char *) &rbd, sizeof(rbd));
-
-#ifdef DEBUG_RX_ERROR
-	  if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF)
-	    printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n",
-		   dev->name);
-
-	  if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F)
-	    printk(KERN_INFO "%s: wv_receive(): missing F flag.\n",
-		   dev->name);
-#endif
-
-	  pkt_len = rbd.rbd_status & RBD_STATUS_ACNT;
-
-	  /* Read the packet and transmit to Linux */
-	  wv_packet_read(dev, rbd.rbd_bufl, pkt_len);
-	}	/* if frame has data */
-
X       fd.fd_status = 0;
X       obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
X 		  (unsigned char *) &fd.fd_status, sizeof(fd.fd_status));
@@ -2775,7 +2758,7 @@
X   /*
X    * Data
X    */
-  obram_write(ioaddr, buf_addr, buf, clen);
+  obram_write(ioaddr, buf_addr, buf, length);
X 
X   /*
X    * Overwrite the predecessor NOP link
@@ -2950,11 +2933,9 @@
X 		(unsigned char *)&psa.psa_quality_thr, 1);
X       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa,
X 		(unsigned char *)&psa.psa_conf_status, 1);
-#ifdef SET_PSA_CRC
X       /* update the Wavelan checksum */
X       update_psa_checksum(dev, ioaddr, lp->hacr);
X #endif
-#endif
X     }
X 
X   /* Zero the mmc structure. */
@@ -3125,7 +3106,7 @@
X 
X   if(i <= 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n",
X 	     dev->name);
X #endif
@@ -3229,7 +3210,7 @@
X 
X   if(i <= 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n",
X 	     dev->name);
X #endif
@@ -3316,7 +3297,7 @@
X 
X   if(i <= 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n",
X 	     dev->name);
X #endif
@@ -3336,7 +3317,7 @@
X 
X   if (i <= 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
X 	     dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
X #endif
@@ -3357,7 +3338,7 @@
X   obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
X   if(cb.ac_status & AC_SFLD_FAIL)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n",
X 	     dev->name);
X #endif
@@ -3638,13 +3619,16 @@
X   wv_ints_on(dev);
X 
X   /* Start card functions */
-  if((wv_ru_start(dev) < 0) ||
-     (wv_cu_start(dev) < 0))
+  if(wv_cu_start(dev) < 0)
X     return -1;
X 
-  /* Finish configuration. */
+  /* Setup the controller and parameters */
X   wv_82586_config(dev);
X 
+  /* Finish configuration with the receive unit */
+  if(wv_ru_start(dev) < 0)
+    return -1;
+
X #ifdef DEBUG_CONFIG_TRACE
X   printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
X #endif
@@ -3945,7 +3929,7 @@
X   /* Check irq */
X   if(dev->irq == 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
X #endif
X       return -ENXIO;
@@ -3953,7 +3937,7 @@
X 
X   if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
X #endif
X       return -EAGAIN;
@@ -3968,7 +3952,7 @@
X   else
X     {
X       free_irq(dev->irq, dev);
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n",
X 	     dev->name);
X #endif
@@ -4065,10 +4049,8 @@
X #endif
X 	  psa_write(ioaddr, HACR_DEFAULT,
X 		    psaoff(0, psa_int_req_no), &irq_mask, 1);
-#ifdef SET_PSA_CRC
X 	  /* update the Wavelan checksum */
X 	  update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
-#endif
X 	  wv_hacr_reset(ioaddr);
X 	}
X     }
@@ -4122,7 +4104,9 @@
X   dev->hard_start_xmit = wavelan_packet_xmit;
X   dev->get_stats = wavelan_get_stats;
X   dev->set_multicast_list = &wavelan_set_multicast_list;
+#ifdef SET_MAC_ADDRESS
X   dev->set_mac_address = &wavelan_set_mac_address;
+#endif	/* SET_MAC_ADDRESS */
X 
X #ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
X   dev->do_ioctl = wavelan_ioctl;
@@ -4176,7 +4160,7 @@
X   /* Don't probe at all. */
X   if(base_addr < 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n",
X 	     dev->name);
X #endif
@@ -4259,7 +4243,7 @@
X   /* If probing is asked */
X   if(io[0] == 0)
X     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X       printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
X       printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
X #endif
@@ -4303,7 +4287,7 @@
X 	}	/* if there is something at the address */
X     }		/* Loop on all addresses. */
X 
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
X   if(wavelan_list == (net_local *) NULL)
X     printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
X #endif
diff -u --recursive --new-file v2.2.7/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.2.7/linux/drivers/net/wavelan.p.h	Tue Mar 23 14:35:48 1999
+++ linux/drivers/net/wavelan.p.h	Thu Apr 29 11:53:41 1999
@@ -34,16 +34,22 @@
X  *	I try to maintain a web page with the Wireless LAN Howto at :
X  *		http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html
X  *
+ * Debugging and options
+ * ---------------------
+ *	You will find below a set of '#define" allowing a very fine control
+ *	on the driver behaviour and the debug messages printed.
+ *	The main options are :
+ *	o SET_PSA_CRC, to have your card correctly recognised by
+ *	  an access point and the Point-to-Point diagnostic tool.
+ *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
+ *	  (otherwise we always start afresh with some defaults)
+ *
X  * wavelan.o is too darned big
X  * ---------------------------
X  *	That's true!  There is a very simple way to reduce the driver
X  *	object by 33%!  Comment out the following line:
X  *		#include <linux/wireless.h>
- *
- * Debugging and options
- * ---------------------
- *	You will find below a set of '#define" allowing a very fine control
- *	on the driver behaviour and the debug messages printed.
+ *	Other compile options can also reduce the size of it...
X  *
X  * MAC address and hardware detection:
X  * -----------------------------------
@@ -274,7 +280,17 @@
X  *	- Correct i82586 configuration parameters
X  *	- Encryption initialisation bug (Robert McCormack)
X  *	- New mac addresses detected in the probe
- *	- Increase watchdog for busy envirnoments
+ *	- Increase watchdog for busy environments
+ *
+ * Changes made for release in 2.0.38 & 2.2.7 :
+ * ------------------------------------------
+ *	- Correct the reception logic to better report errors and avoid
+ *	  sending bogus packet up the stack
+ *	- Delay RU config to avoid corrupting first received packet
+ *	- Change config completion code (to actually check something)
+ *	- Avoid reading out of bound in skbuf to transmit
+ *	- Rectify a lot of (useless) debugging code
+ *	- Change the way to `#ifdef SET_PSA_CRC'
X  *
X  * Wishes & dreams:
X  * ----------------
@@ -315,6 +331,24 @@
X #include	"i82586.h"
X #include	"wavelan.h"
X 
+/************************** DRIVER OPTIONS **************************/
+/*
+ * `#define' or `#undef' the following constant to change the behaviour
+ * of the driver...
+ */
+#undef SET_PSA_CRC		/* Calculate and set the CRC on PSA (slower) */
+#define USE_PSA_CONFIG		/* Use info from the PSA. */
+#undef STRUCT_CHECK		/* Verify padding of structures. */
+#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
+#undef SET_MAC_ADDRESS		/* Experimental */
+
+#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
+/* Warning:  this stuff will slow down the driver. */
+#define WIRELESS_SPY		/* Enable spying addresses. */
+#undef HISTOGRAM		/* Enable histogram of signal level. */
+#endif
+
X /****************************** DEBUG ******************************/
X 
X #undef DEBUG_MODULE_TRACE	/* module insertion/removal */
@@ -324,14 +358,16 @@
X #define DEBUG_INTERRUPT_ERROR	/* problems */
X #undef DEBUG_CONFIG_TRACE	/* Trace the config functions. */
X #undef DEBUG_CONFIG_INFO	/* what's going on */
-#define DEBUG_CONFIG_ERRORS	/* errors on configuration */
+#define DEBUG_CONFIG_ERROR	/* errors on configuration */
X #undef DEBUG_TX_TRACE		/* transmission calls */
X #undef DEBUG_TX_INFO		/* header of the transmitted packet */
-#define DEBUG_TX_ERROR		/* unexpected conditions */
+#undef DEBUG_TX_FAIL		/* Normal failure conditions */
+#define DEBUG_TX_ERROR		/* Unexpected conditions */
X #undef DEBUG_RX_TRACE		/* transmission calls */
-#undef DEBUG_RX_INFO		/* header of the transmitted packet */
-#define DEBUG_RX_ERROR		/* unexpected conditions */
-#undef DEBUG_PACKET_DUMP	16	/* Dump packet on the screen. */
+#undef DEBUG_RX_INFO		/* header of the received packet */
+#undef DEBUG_RX_FAIL		/* Normal failure conditions */
+#define DEBUG_RX_ERROR		/* Unexpected conditions */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen. */
X #undef DEBUG_IOCTL_TRACE	/* misc. call by Linux */
X #undef DEBUG_IOCTL_INFO		/* various debugging info */
X #define DEBUG_IOCTL_ERROR	/* what's going wrong */
@@ -343,26 +379,10 @@
X #undef DEBUG_I82586_SHOW	/* Show i82586 status. */
X #undef DEBUG_DEVICE_SHOW	/* Show device parameters. */
X 
-/* Options */
-#define USE_PSA_CONFIG		/* Use info from the PSA. */
-#define SET_PSA_CRC		/* Calculate and set the CRC on PSA */
-#define IGNORE_NORMAL_XMIT_ERRS	/* Don't bother with normal conditions. */
-#undef STRUCT_CHECK		/* Verify padding of structures. */
-#undef OLDIES			/* old code (to redo) */
-#undef RECORD_SNR		/* to redo */
-#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
-#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
-
-#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
-/* Warning:  this stuff will slow down the driver. */
-#define WIRELESS_SPY		/* Enable spying addresses. */
-#undef HISTOGRAM		/* Enable histogram of signal level. */
-#endif
-
X /************************ CONSTANTS & MACROS ************************/
X 
X #ifdef DEBUG_VERSION_SHOW
-static const char	*version	= "wavelan.c : v18 (wireless extensions) 18/2/99\n";
+static const char	*version	= "wavelan.c : v19 (wireless extensions) 20/4/99\n";
X #endif
X 
X /* Watchdog temporisation */
diff -u --recursive --new-file v2.2.7/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.2.7/linux/drivers/sbus/char/pcikbd.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/sbus/char/pcikbd.c	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.26 1999/04/28 11:55:42 davem Exp $
+/* $Id: pcikbd.c,v 1.27 1999/05/09 06:40:47 ecd Exp $
X  * pcikbd.c: Ultra/AX PC keyboard support.
X  *
X  * Copyright (C) 1997  Eddie C. Dost  (e...@skynet.be)
@@ -276,6 +276,7 @@
X 		prev_scancode = 0;
X 		return 0;
X 	}
+	scancode &= 0x7f;
X 	if(prev_scancode) {
X 		if(prev_scancode != 0xe0) {
X 			if(prev_scancode == 0xe1 && scancode == 0x1d) {
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.2.7/linux/drivers/scsi/Config.in	Fri Apr 16 14:47:30 1999
+++ linux/drivers/scsi/Config.in	Thu Apr 29 11:53:41 1999
@@ -55,9 +55,7 @@
X dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
X dep_tristate 'Future Domain 16xx SCSI/AHA-2920A support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
X if [ "$CONFIG_MCA" = "y" ]; then
-  if [ "$CONFIG_SCSI" = "y" ]; then
-    bool 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS
-  fi
+    dep_tristate 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS $CONFIG_SCSI
X fi
X dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
X dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.2.7/linux/drivers/scsi/Makefile	Fri Apr 16 14:47:30 1999
+++ linux/drivers/scsi/Makefile	Thu Apr 29 11:53:41 1999
@@ -533,8 +533,11 @@
X 
X ifeq ($(CONFIG_SCSI_FD_MCS),y)
X L_OBJS += fd_mcs.o
+else
+  ifeq ($(CONFIG_SCSI_FD_MCS),m)
+  M_OBJS += fd_mcs.o
+  endif
X endif
-
X 
X ifeq ($(CONFIG_SCSI_T128),y)
X L_OBJS += t128.o
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/README.ibmmca linux/drivers/scsi/README.ibmmca
--- v2.2.7/linux/drivers/scsi/README.ibmmca	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/README.ibmmca	Mon May 10 13:00:10 1999
@@ -0,0 +1,979 @@
+
+
+               -=< The IBM Microchannel SCSI-Subsystem >=-
+	       
+	                 for the IBM PS/2 series
+		 
+	  	   Low Level Software-Driver for Linux
+		 
+     Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU 
+  General Public License. Originally written by Martin Kolinek, December 1995.
+         Officially maintained by Michael Lang since January 1999.
+	   
+ 	                       Version 3.1e
+	
+	
+   Last update: 20 February 1999
+
+
+   Authors of this Driver
+   ----------------------
+    - Chris Beauregard (improvement of the SCSI-device mapping by the driver)
+    - Martin Kolinek (origin, first release of this driver)
+    - Klaus Kudielka (multiple SCSI-host management/detection, adaption to
+                      Linux Kernel 2.1.x, module support)
+    - Michael Lang (assigning original pun,lun mapping, dynamical ldn 
+                    assignment, this file, patch, official driver maintenance)
+
+   Table of Contents
+   -----------------
+   1 Abstract
+   2 Driver Description
+     2.1  IBM SCSI-Subsystem Detection
+     2.2  Physical Units, Logical Units, and Logical Devices
+     2.3  SCSI-Device Recognition and dynamical ldn Assignment
+     2.4  SCSI-Device Order
+     2.5  Regular SCSI-Command-Processing
+     2.6  Abort & Reset Commands
+     2.7  Disk Geometry
+     2.8  Kernel Boot Option
+     2.9  Driver Module Support
+     2.10 Multiple Hostadapter Support
+     2.11 /proc/scsi-Filesystem Information
+     2.12 /proc/mca-Filesystem Information
+     2.13 Supported IBM SCSI-Subsystems
+     2.14 Linux Kernel Versions
+   3 Code History
+   4 To do
+   5 Users' Manual
+     5.1 Commandline Parameters
+     5.2 Troubleshooting
+     5.3 Bugreports
+     5.4 Support WWW-page
+   6 References
+   7 Trademarks
+
+                              * * *
+
+   1 Abstract
+   ----------
+   This README-file describes the IBM SCSI-subsystem low level driver for 
+   Linux. The descriptions which were formerly kept in the source-code have 
+   been taken out to this file to easify the codes' readability. The driver 
+   description has been updated, as most of the former description was already
+   quite outdated. The history of the driver development is also kept inside 
+   here. Multiple historical developments have been summarized to shorten the 
+   textsize a bit. At the end of this file you can find a small manual for 
+   this driver and hints to get it running even on your machine (hopefully).
+
+   2 Driver Description
+   --------------------
+   2.1 IBM SCSI-Subsystem Detection
+   --------------------------------
+   This is done in the ibmmca_detect() function. It first checks, if the
+   Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the
+   Microchannel. In a next step, a free interrupt is chosen and the main
+   interrupt handler is connected to it to handle answers of the SCSI-
+   subsystem(s). In a further step, it is checked, wether there was a forced
+   detection of the adapter via the kernel commandline, where the I/O port
+   and the SCSI-subsystem id can be specified. The next step checks if there
+   is an integrated SCSI-subsystem installed. This register area is fixed 
+   through all IBM PS/2 MCA-machines and appears as something like a virtual 
+   slot 10 of the MCA-bus. If POS-register 2 is not 0xff, there must be a SCSI-
+   subsystem present and it will be registered as IBM Integrated SCSI-
+   Subsystem. The next step checks, if there is a slot-adapter installed on 
+   the MCA-bus. To get this, the first two POS-registers, that represent the 
+   adapter ID are checked. If they fit to one of the ids, stored in the 
+   adapter list, a SCSI-subsystem is assumed to be found and will be 
+   registered. This check is done through all possible MCA-bus slots to allow 
+   more than one SCSI-adapter to be present in the PS/2-system and this is 
+   already the first point of problems. Looking into the technical reference 
+   manual for the IBM PS/2 common interfaces, the POS2 register must have 
+   different interpretation of its single bits. While one can assume, that the
+   integrated subsystem has a fix I/O-address at 0x3540 - 0x3547, further
+   installed IBM SCSI-adapters must use a different I/O-address. This is
+   expressed by bit 1 to 3 of POS2 (multiplied by 8 + 0x3540). Bits 2 and 3 
+   are reserved for the integrated subsystem, but not for the adapters! The
+   following list shows, how the bits of POS2 and POS3 should be interpreted.
+   
+   The POS2-register of all PS/2 models' integrated SCSI-subsystems has the 
+   following interpretation of bits:
+                           Bit 7 - 4 : Chip Revision ID (Release)
+                           Bit 3 - 2 : Reserved
+                           Bit 1     : 8k NVRAM Disabled
+                           Bit 0     : Chip Enable (EN-Signal)
+   The POS3-register is interpreted as follows (for ALL IBM SCSI-subsys.):
+                           Bit 7 - 5 : SCSI ID
+                           Bit 4 - 0 : Reserved = 0
+   (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
+   Interfaces (1991)"). 
+   In short words, this means, that IBM PS/2 machines only support 1 single 
+   subsystem by default. But (additional) slot-adapters must have another 
+   configuration on pos2 in order to be enabled to use more than one IBM SCSI-
+   subsystem, e.g. for a network server. From tests with the IBM SCSI Adapter 
+   w/cache, the POS2-register for slot adapters should be interpreted in the 
+   following way:
+                           Bit 7 - 4 : Chip Revision ID (Release)
+                           Bit 3 - 1 : port offset factor ( * 8 + 0x3540 )
+                           Bit 0     : Chip Enable (EN-Signal)
+
+   One day I found a patch in ibmmca_detect(), forcing the I/O-address to be 
+   0x3540 for integrated SCSI-subsystems, there was a remark placed, that on 
+   integrated IBM SCSI-subsystems of model 56, the POS2 register was showing 5.
+   This means, that really for these models, POS2 has to be interpreted
+   sticking to the technical reference guide. In this case, the bit 2 (4) is 
+   a reserved bit and may not be interpreted. These differences between the 
+   adapters and the integrated controllers are taken into account by the 
+   detection routine of the driver on from version >3.0g. 
+
+   Every time, a SCSI-subsystem is discovered, the ibmmca_register() function
+   is called. This function checks first, if the requested area for the I/O-
+   address of this SCSI-subsystem is still available and assigns this I/O-
+   area to the SCSI-subsystem. There are always 8 sequential I/O-addresses
+   taken for each individual SCSI-subsystem found, which are:
+   
+     Offset            Type                  Permissions
+       0     Command Interface Register 1    Read/Write
+       1     Command Interface Register 2    Read/Write
+       2     Command Interface Register 3    Read/Write
+       3     Command Interface Register 4    Read/Write
+       4     Attention Register              Read/Write
+       5     Basic Control Register          Read/Write
+       6     Interrupt Status Register       Read
+       7     Basic Status Register           Read
+   
+   After the I/O-address range is assigned, the host-adapter is assigned
+   to a local structure which keeps all adapter information needed for the
+   driver itself and the mid- and higher-level SCSI-drivers. The SCSI pun/lun
+   and the adapters' ldn tables are initialized and get probed afterwards by
+   the check_devices() function. If no further adapters are found, 
+   ibmmca_detect() quits.
+   
+   2.2 Physical Units, Logical Units, and Logical Devices
+   ------------------------------------------------------
+   There can be up to 56 devices on the SCSI bus (besides the adapter):
+   there are up to 7 "physical units" (each identified by physical unit 
+   number or pun, also called the scsi id, this is the number you select
+   with hardware jumpers), and each physical unit can have up to 8 
+   "logical units" (each identified by logical unit number, or lun, 
+   between 0 and 7). 
+
+   Typically the adapter has pun=7, so puns of other physical units
+   are between 0 and 6. Almost all physical units have only one   
+   logical unit, with lun=0. A CD-ROM jukebox would be an example of 
+   a physical unit with more than one logical unit.
+
+   The embedded microprocessor of the IBM SCSI-subsystem hides the complex
+   two-dimensional (pun,lun) organization from the operating system.
+   When the machine is powered-up (or rebooted), the embedded microprocessor 
+   checks, on its own, all 56 possible (pun,lun) combinations, and the first 
+   15 devices found are assigned into a one-dimensional array of so-called 
+   "logical devices", identified by "logical device numbers" or ldn. The last 
+   ldn=15 is reserved for the subsystem itself.
+   
+   2.3 SCSI-Device Recognition and dynamical ldn Assignment
+   --------------------------------------------------------
+   One consequence of information hiding is that the real (pun,lun)    
+   numbers are also hidden. The two possibilities to get around this problem
+   is to offer fake pun/lun combinations to the operating system or to 
+   delete the whole mapping of the adapter and to reassign the ldns, using
+   the immediate assign command of the SCSI-subsystem. At the beginning of the
+   development of this driver, the following approach was used:
+   First, the driver checked the ldn's (0 to 6) to find out which ldn's
+   have devices assigned. This was done by the functions check_devices() and
+   device_exists(). The interrupt handler has a special paragraph of code
+   (see local_checking_phase_flag) to assist in the checking. Assume, for
+   example, that three logical devices were found assigned at ldn 0, 1, 2.
+   These are presented to the upper layer of Linux SCSI driver
+   as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0). 
+   On the other hand, if the upper layer issues a command to device
+   say (4,0), this driver returns DID_NO_CONNECT error.
+
+   In a second step of the driver development, the following improvement has
+   been applied: The first approach limited the number of devices to 7, far
+   fewer than the 15 that it could usem then it just maped ldn -> 
+   (ldn/8,ldn%8) for pun,lun.  We ended up with a real mishmash of puns
+   and luns, but it all seemed to work.
+
+   The latest development, which is implemented from the driver version 3.0
+   and later, realizes the device recognition in the following way:
+   The physical SCSI-devices on the SCSI-bus are probed via immediate_assign- 
+   and device_inquiry-commands, that is all implemented in a completely new
+   made check_devices() subroutine. This delivers a exact map of the physical
+   SCSI-world that is now stored in the get_scsi[][]-array. This means,
+   that the once hidden pun,lun assignment is now known to this driver.
+   It no longer believes in default-settings of the subsystem and maps all
+   ldns to existing pun,lun "by foot". This assures full control of the ldn
+   mapping and allows dynamical remapping of ldns to different pun,lun, if
+   there are more SCSI-devices installed than ldns available (n>15). The
+   ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0,
+   excluding the pun of the subsystem. This assures, that at least simple 
+   SCSI-installations have optimum access-speed and are not touched by
+   dynamical remapping. The ldns 7 to 14 are put to existing devices with 
+   lun>0 or to non-existing devices, in order to satisfy the subsystem, if 
+   there are less than 15 SCSI-devices connected. In the case of more than 15 
+   devices, the dynamical mapping goes active. If the get_scsi[][] reports a 
+   device to be existant, but it has no ldn assigned, it gets a ldn out of 7 
+   to 14. The numbers are assigned in cyclic order. Therefore it takes 8 
+   dynamical reassignments on the SCSI-devices, until a certain device 
+   looses its ldn again. This assures, that dynamical remapping is avoided 
+   during intense I/O between up to 15 SCSI-devices (means pun,lun 
+   combinations). A further advantage of this method is, that people who
+   build their kernel without probing on all luns will get what they expect,
+   because the driver just won't assign everything with lun>0 when 
+   multpile lun probing is inactive.
+ 
+   2.4 SCSI-Device Order
+   ---------------------
+   Because of the now correct recognition of physical pun,lun, and 
+   their report to mid-level- and higher-level-drivers, the new reported puns
+   can be different from the old, faked puns. Therefore, Linux will eventually
+   change /dev/sdXXX assignments and prompt you for corrupted superblock
+   repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
+   You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file
+   entries right. After that, the system should come up as errorfree as before.
+   If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
+   in a Linux session booted on old kernel and run lilo before reboot. Check
+   lilo.conf anyway to get boot on other partitions with foreign OSes right
+   again. But there exists a feature of this driver that allows you to change
+   the assignment order of the SCSI-devices by flipping the PUN-assignment.
+   See the next paragraph for a description.
+ 
+   The problem for this is, that Linux does not assign the SCSI-devices in the
+   way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to 
+   the device with at minimum id 0. But the first drive should be at id 6,
+   because for historical reasons, drive at id 6 has, by hardware, the highest
+   priority and a drive at id 0 the lowest. IBM was one of the rare producers,
+   where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most 
+   other producers' BIOS does not (I think even Adaptec-BIOS). The 
+   IBMMCA_SCSI_ORDER_STANDARD flag, which you set while configuring the
+   kernel enables to choose the preferred way of SCSI-device-assignment. 
+   Defining this flag would result in Linux determining the devices in the 
+   same order as DOS and OS/2 does on your MCA-machine. This is also standard 
+   on most industrial computers and OSes, like e.g. OS-9. Leaving this flag 
+   undefined will get your devices ordered in the default way of Linux. See 
+   also the remarks of Chris Beauregard from Dec 15, 1997 and the followups 
+   in section 3.
+   
+   2.5 Regular SCSI-Command-Processing
+   -----------------------------------
+   Only three functions get involved: ibmmca_queuecommand(), issue_cmd(),
+   and interrupt_handler().
+
+   The upper layer issues a scsi command by calling function 
+   ibmmca_queuecommand(). This function fills a "subsystem control block"
+   (scb) and calls a local function issue_cmd(), which writes a scb 
+   command into subsystem I/O ports. Once the scb command is carried out, 
+   the interrupt_handler() is invoked. If a device is determined to be 
+   existant and it has not assigned any ldn, it gets one dynamically.
+   For this, the whole stuff is done in ibmmca_queuecommand().
+
+   2.6 Abort & Reset Commands
+   --------------------------
+   These are implemented with busy waiting for interrupt to arrive.
+   ibmmca_reset() and ibmmca_abort() do not work sufficently well
+   up to now and need still a lot of development work. But, this seems
+   to be even a problem with other SCSI-low level drivers, too. However,
+   this should be no excuse.
+
+   2.7 Disk Geometry
+   -----------------
+   The ibmmca_biosparams() function should return the same disk geometry 
+   as the bios. This is needed for fdisk, etc. The returned geometry is 
+   certainly correct for disks smaller than 1 gigabyte. In the meantime,
+   it has been proved, that this works fine even with disks larger than
+   1 gigabyte.
+
+   2.8 Kernel Boot Option
+   ----------------------
+   The function ibmmca_scsi_setup() is called if option ibmmcascsi=n 
+   is passed to the kernel. See file linux/init/main.c for details.
+   
+   2.9 Driver Module Support
+   -------------------------
+   Is implemented and tested by K. Kudielka. This could probably not work
+   on kernels <2.1.0.
+  
+   2.10 Multiple Hostadapter Support
+   ---------------------------------
+   This driver supports up to eight interfaces of type IBM-SCSI-Subsystem. 
+   Integrated-, and MCA-adapters are automatically recognized. Unrecognizable
+   IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters.
+ 
+   2.11 /proc/scsi-Filesystem Information
+   --------------------------------------
+   Information about the driver condition is given in 
+   /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
+   
+   This table is quite informative for interested users. It shows the load
+   of commands on the subsystem and wether you are running the bypassed 
+   (software) or integrated (hardware) SCSI-command set (see below). The
+   amount of accesses is shown. Read, write, modeselect is shown seperately
+   in order to help debugging problems with CD-ROMs or tapedrives.
+   
+   The following table shows the list of 15 logical device numbers, that are
+   used by the SCSI-subsystem. The load on each ldn is shown in the table,
+   again, read and write commands are split. The last column shows the amount
+   of reassignments, that have been applied to the ldns, if you have more than
+   15 pun/lun combinations available on the SCSI-bus.
+   
+   The last two tables show the pun/lun map and the positions of the ldns
+   on this pun/lun map. This may change during operation, when a ldn is
+   reassigned to another pun/lun combination. If the necessity for dynamical
+   assignments is set to 'no', the ldn structure keeps static.
+   
+   2.12 /proc/mca-Filesystem Information
+   -------------------------------------
+   The slot-file contains all default entries and in addition chip and I/O-
+   address information of the SCSI-subsystem. This information is provided
+   by ibmmca_getinfo().
+   
+   2.13 Supported IBM SCSI-Subsystems
+   ----------------------------------
+   The following IBM SCSI-subsystems are supported by this driver:
+   
+     - IBM Fast SCSI-2 Adapter
+     - IBM 7568 Industrial Computer SCSI Adapter w/cache
+     - IBM Expansion Unit SCSI Controller
+     - IBM SCSI Adapter w/Cache
+     - IBM SCSI Adapter
+     - IBM Integrated SCSI Controller
+     
+   2.14 Linux Kernel Versions
+   --------------------------
+   The IBM SCSI-subsystem low level driver is prepared to be used with
+   all versions of Linux between 2.0.x and 2.2.x. The compatibility checks
+   are fully implemented up from version 3.1e of the driver. This means, that
+   you just need the latest ibmmca.h and ibmmca.c file and copy it in the
+   linux/drivers/scsi directory. The code is automatically adapted during 
+   kernel compilation.
+
+   3 Code History
+   --------------
+   Jan 15 1996:  First public release.
+   - Martin Kolinek
+
+   Jan 23 1996:  Scrapped code which reassigned scsi devices to logical
+   device numbers. Instead, the existing assignment (created
+   when the machine is powered-up or rebooted) is used. 
+   A side effect is that the upper layer of Linux SCSI 
+   device driver gets bogus scsi ids (this is benign), 
+   and also the hard disks are ordered under Linux the 
+   same way as they are under dos (i.e., C: disk is sda, 
+   D: disk is sdb, etc.).
+   - Martin Kolinek
+
+   I think that the CD-ROM is now detected only if a CD is 
+   inside CD_ROM while Linux boots. This can be fixed later,
+   once the driver works on all types of PS/2's.
+   - Martin Kolinek
+
+   Feb 7 1996:   Modified biosparam function. Fixed the CD-ROM detection. 
+   For now, devices other than harddisk and CD_ROM are 
+   ignored. Temporarily modified abort() function 
+   to behave like reset().
+   - Martin Kolinek
+
+   Mar 31 1996:  The integrated scsi subsystem is correctly found
+   in PS/2 models 56,57, but not in model 76. Therefore
+   the ibmmca_scsi_setup() function has been added today.
+   This function allows the user to force detection of
+   scsi subsystem. The kernel option has format
+   ibmmcascsi=n
+   where n is the scsi_id (pun) of the subsystem. Most likely, n is 7.
+   - Martin Kolinek
+
+   Aug 21 1996:  Modified the code which maps ldns to (pun,0).  It was
+   insufficient for those of us with CD-ROM changers.
+   - Chris Beauregard
+ 
+   Dec 14 1996: More improvements to the ldn mapping.  See check_devices
+   for details.  Did more fiddling with the integrated SCSI detection,
+   but I think it's ultimately hopeless without actually testing the
+   model of the machine.  The 56, 57, 76 and 95 (ultimedia) all have
+   different integrated SCSI register configurations.  However, the 56
+   and 57 are the only ones that have problems with forced detection.
+   - Chris Beauregard
+ 
+   Mar 8-16 1997: Modified driver to run as a module and to support 
+   multiple adapters. A structure, called ibmmca_hostdata, is now
+   present, containing all the variables, that were once only
+   available for one single adapter. The find_subsystem-routine has vanished.
+   The hardware recognition is now done in ibmmca_detect directly.
+   This routine checks for presence of MCA-bus, checks the interrupt
+   level and continues with checking the installed hardware.
+   Certain PS/2-models do not recognize a SCSI-subsystem automatically.
+   Hence, the setup defined by command-line-parameters is checked first.
+   Thereafter, the routine probes for an integrated SCSI-subsystem.
+   Finally, adapters are checked. This method has the advantage to cover all
+   possible combinations of multiple SCSI-subsystems on one MCA-board. Up to
+   eight SCSI-subsystems can be recognized and announced to the upper-level
+   drivers with this improvement. A set of defines made changes to other
+   routines as small as possible.
+   - Klaus Kudielka
+   
+   May 30 1997: (v1.5b)
+   1) SCSI-command capability enlarged by the recognition of MODE_SELECT.
+      This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which 
+      allows data to be written from the system to the device. It is a
+      necessary step to be allowed to set blocksize of SCSI-tape-drives and 
+      the tape-speed, whithout confusing the SCSI-Subsystem.
+   2) The recognition of a tape is included in the check_devices routine.
+      This is done by checking for TYPE_TAPE, that is already defined in
+      the kernel-scsi-environment. The markup of a tape is done in the 
+      global ldn_is_tape[] array. If the entry on index ldn 
+      is 1, there is a tapedrive connected.
+   3) The ldn_is_tape[] array is necessary to distinguish between tape- and 
+      other devices. Fixed blocklength devices should not cause a problem
+      with the SCB-command for read and write in the ibmmca_queuecommand
+      subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for
+      the tape-devices, as recommended by IBM in this Technical Reference,
+      mentioned below. (IBM recommends to avoid using the read/write of the
+      subsystem, but the fact was, that read/write causes a command error from
+      the subsystem and this causes kernel-panic.)
+   4) In addition, I propose to use the ldn instead of a fix char for the
+      display of PS2_DISK_LED_ON(). On 95, one can distinguish between the
+      devices that are accessed. It shows activity and easyfies debugging.   
+   The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2
+   (I do not know yet the type). Optimization and CD-ROM audio-support, 
+   I am working on ...
+   - Michael Lang
+   
+   June 19 1997: (v1.6b)
+   1) Submitting the extra-array ldn_is_tape[] -> to the local ld[]
+      device-array. 
+   2) CD-ROM Audio-Play seems to work now.
+   3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code
+      0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears 
+      also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that 
+      the problem is independent of the low-level-driver/bus-architecture.
+   4) Hexadecimal ldn on PS/2-95 LED-display.
+   5) Fixing of the PS/2-LED on/off that it works right with tapedrives and
+      does not confuse the disk_rw_in_progress counter.
+   - Michael Lang
+  
+   June 21 1997: (v1.7b)
+   1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/<host> the
+      outer-world about operational load statistics on the different ldns,
+      seen by the driver. Everybody that has more than one IBM-SCSI should
+      test this, because I only have one and cannot see what happens with more
+      than one IBM-SCSI hosts.
+   2) Definition of a driver version-number to have a better recognition of 
+      the source when there are existing too much releases that may confuse
+      the user, when reading about release-specific problems. Up to know,
+      I calculated the version-number to be 1.7. Because we are in BETA-test
+      yet, it is today 1.7b.
+   3) Sorry for the heavy bug I programmed on June 19 1997! After that, the
+      CD-ROM did not work any more! The C7-command was a fake impression
+      I got while programming. Now, the READ and WRITE commands for CD-ROM are
+      no longer running over the subsystem, but just over 
+      IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts
+      much faster(!) and hopefully all fancy multimedia-functions, like direct
+      digital recording from audio-CDs also work. (I tried it with cdda2wav
+      from the cdwtools-package and it filled up the harddisk immediately :-).)
+      To easify boolean logics, a further local device-type in ld[], called
+      is_cdrom has been included.
+   4) If one uses a SCSI-device of unsupported type/commands, one
+      immediately runs into a kernel-panic caused by Command Error. To better
+      understand which SCSI-command caused the problem, I extended this
+      specific panic-message slightly.
+   - Michael Lang
+ 
+   June 25 1997: (v1.8b)
+   1) Some cosmetical changes for the handling of SCSI-device-types.
+      Now, also CD-Burners / WORMs and SCSI-scanners should work. For
+      MO-drives I have no experience, therefore not yet supported.
+      In logical_devices I changed from different type-variables to one
+      called 'device_type' where the values, corresponding to scsi.h,
+      of a SCSI-device are stored.
+   2) There existed a small bug, that maps a device, coming after a SCSI-tape
+      wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong
+      -> problem removed.
+   3) Extension of the logical_device structure. Now it contains also device,
+      vendor and revision-level of a SCSI-device for internal usage.
+   - Michael Lang
+
+   June 26-29 1997: (v2.0b)
+   1) The release number 2.0b is necessary because of the completely new done
+      recognition and handling of SCSI-devices with the adapter. As I got
+      from Chris the hint, that the subsystem can reassign ldns dynamically,
+      I remembered this immediate_assign-command, I found once in the handbook.
+      Now, the driver first kills all ldn assignments that are set by default
+      on the SCSI-subsystem. After that, it probes on all puns and luns for
+      devices by going through all combinations with immediate_assign and
+      probing for devices, using device_inquiry. The found physical(!) pun,lun
+      structure is stored in get_scsi[][] as device types. This is followed
+      by the assignment of all ldns to existing SCSI-devices. If more ldns
+      than devices are available, they are assigned to non existing pun,lun
+      combinations to satisfy the adapter. With this, the dynamical mapping
+      was possible to implement. (For further info see the text in the 
+      source-code and in the description below. Read the description
+      below BEFORE installing this driver on your system!)
+   2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION.
+   3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID
+      (pun) of the accessed SCSI-device. This is now senseful, because the 
+      pun known within the driver is exactly the pun of the physical device
+      and no longer a fake one.
+   4) The /proc/scsi/ibmmca/<host_no> consists now of the first part, where
+      hit-statistics of ldns is shown and a second part, where the maps of 
+      physical and logical SCSI-devices are displayed. This could be very 
+      interesting, when one is using more than 15 SCSI-devices in order to 
+      follow the dynamical remapping of ldns.
+   - Michael Lang
+ 
+   June 26-29 1997: (v2.0b-1)
+   1) I forgot to switch the local_checking_phase_flag to 1 and back to 0
+      in the dynamical remapping part in ibmmca_queuecommand for the 
+      device_exist routine. Sorry.
+   - Michael Lang
+ 
+   July 1-13 1997: (v3.0b,c)
+   1) Merging of the driver-developments of Klaus Kudielka and Michael Lang 
+      in order to get a optimum and unified driver-release for the 
+      IBM-SCSI-Subsystem-Adapter(s).
+         For people, using the Kernel-release >=2.1.0, module-support should 
+      be no problem. For users, running under <2.1.0, module-support may not 
+      work, because the methods have changed between 2.0.x and 2.1.x.
+   2) Added some more effective statistics for /proc-output.
+   3) Change typecasting at necessary points from (unsigned long) to
+      virt_to_bus().
+   4) Included #if... at special points to have specific adaption of the
+      driver to kernel 2.0.x and 2.1.x. It should therefore also run with 
+      later releases.
+   5) Magneto-Optical drives and medium-changers are also recognized, now.
+      Therefore, we have a completely gapfree recognition of all SCSI-
+      device-types, that are known by Linux up to kernel 2.1.31.
+   6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within
+      the configuration, each connected SCSI-device will get a reset command
+      during boottime. This can be necessary for some special SCSI-devices.
+      This flag should be included in Config.in.
+      (See also the new Config.in file.)
+   Probable next improvement: bad disk handler.
+   - Michael Lang
+ 
+   Sept 14 1997: (v3.0c)
+   1) Some debugging and speed optimization applied.
+   - Michael Lang
+
+   Dec 15, 1997
+    - chr...@truespectra.com
+    - made the front panel display thingy optional, specified from the
+    command-line via ibmmcascsi=display.  Along the lines of the /LED
+    option for the OS/2 driver.
+    - fixed small bug in the LED display that would hang some machines.
+    - reversed ordering of the drives (using the
+    IBMMCA_SCSI_ORDER_STANDARD define).  This is necessary for two main
+    reasons:
+	- users who've already installed Linux won't be screwed.  Keep
+	in mind that not everyone is a kernel hacker.
+	- be consistent with the BIOS ordering of the drives.  In the
+	BIOS, id 6 is C:, id 0 might be D:.  With this scheme, they'd be
+	backwards.  This confuses the crap out of those heathens who've
+	got a impure Linux installation (which, <wince>, I'm one of).
+    This whole problem arises because IBM is actually non-standard with
+    the id to BIOS mappings.  You'll find, in fdomain.c, a similar
+    comment about a few FD BIOS revisions.  The Linux (and apparently
+    industry) standard is that C: maps to scsi id (0,0).  Let's stick
+    with that standard.
+    - Since this is technically a branch of my own, I changed the
+    version number to 3.0e-cpb.
+
+   Jan 17, 1998: (v3.0f)
+   1) Addition of some statistical info for /proc in proc_info.
+   2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15
+      1997. In fact, IBM is right, concerning the assignment of SCSI-devices 
+      to driveletters. It is conform to the ANSI-definition of the SCSI-
+      standard to assign drive C: to SCSI-id 6, because it is the highest
+      hardware priority after the hostadapter (that has still today by
+      default everywhere id 7). Also realtime-operating systems that I use, 
+      like LynxOS and OS9, which are quite industrial systems use top-down
+      numbering of the harddisks, that is also starting at id 6. Now, one
+      sits a bit between two chairs. On one hand side, using the define
+      IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to
+      the IBM- and ANSI-SCSI-standard and keeps this driver downward
+      compatible to older releases, on the other hand side, people is quite
+      habituated in believing that C: is assigned to (0,0) and much other
+      SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD 
+      define out of the driver and put it into Config.in as subitem of 
+      'IBM SCSI support'. A help, added to Documentation/Configure.help 
+      explains the differences between saying 'y' or 'n' to the user, when 
+      IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to 
+      choose the way of assignment, depending on his own situation and gusto.
+   3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is
+      now called IBMMCA_SCSI_DEV_RESET.
+   4) Optimization of proc_info and its subroutines.
+   5) Added more in-source-comments and extended the driver description by
+      some explanation about the SCSI-device-assignment problem.
+   - Michael Lang
+   
+   Jan 18, 1998: (v3.0g)
+   1) Correcting names to be absolutely conform to the later 2.1.x releases.
+      This is necessary for 
+            IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET
+            IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+   - Michael Lang
+ 
+   Jan 18, 1999: (v3.1 MCA-team internal)
+   1) The multiple hosts structure is accessed from every subroutine, so there
+      is no longer the address of the device structure passed from function
+      to function, but only the hostindex. A call by value, nothing more. This
+      should really be understood by the compiler and the subsystem should get
+      the right values and addresses.
+   2) The SCSI-subsystem detection was not complete and quite hugely buggy up
+      to now, compared to the technical manual. The interpretation of the pos2
+      register is not as assumed by people before, therefore, I dropped a note
+      in the ibmmca_detect function to show the registers' interpretation.
+      The pos-registers of integrated SCSI-subsystems do not contain any 
+      information concerning the IO-port offset, really. Instead, they contain
+      some info about the adapter, the chip, the NVRAM .... The I/O-port is
+      fixed to 0x3540 - 0x3547. There can be more than one adapters in the 
+      slots and they get an offset for the I/O area in order to get their own
+      I/O-address area. See chapter 2 for detailed description. At least, the 
+      detection should now work right, even on models other than 95. The 95ers
+      came happily around the bug, as their pos2 register contains always 0 
+      in the critical area. Reserved bits are not allowed to be interpreted, 
+      therefore, IBM is allowed to set those bits as they like and they may 
+      really vary between different PS/2 models. So, now, no interpretation 
+      of reserved bits - hopefully no trouble here anymore.
+   3) The command error, which you may get on models 55, 56, 57, 70, 77 and
+      P70 may have been caused by the fact, that adapters of older design do
+      not like sending commands to non-existing SCSI-devices and will react
+      with a command error as a sign of protest. While this error is not
+      present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI
+      Adapters. Therefore, I implemented a workarround to forgive those 
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 17'
echo 'File patch-2.2.8 is continued in part 18'
echo 18 > _shar_seq_.tmp
#!/bin/sh
# this is part 18 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 18; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+      adapters their protests, but it is marked up in the statisctis, so
+      after a successful boot, you can see in /proc/scsi/ibmmca/<host_number>
+      how often the command errors have been forgiven to the SCSI-subsystem.
+      If the number is bigger than 0, you have a SCSI subsystem of older
+      design, what should no longer matter.
+   4) ibmmca_getinfo() has been adapted very carefully, so it shows in the 
+      slotn file really, what is senseful to be presented.
+   5) ibmmca_register() has been extended in its parameter list in order to
+      pass the right name of the SCSI-adapter to Linux.
+   - Michael Lang
+
+   Feb 6, 1999: (v3.1)
+   1) Finally, after some 3.1Beta-releases, the 3.1 release. Sorry, for 
+      the delayed release, but it was not finished with the release of 
+      Kernel 2.2.0.
+   - Michael Lang
+   
+   Feb 10, 1999 (v3.1)
+   1) Added a new commandline parameter called 'bypass' in order to bypass
+      every integrated subsystem SCSI-command consequently in case of
+      troubles.
+   2) Concatenated read_capacity requests to the harddisks. It gave a lot
+      of troubles with some controllers and after I wanted to apply some
+      extensions, it jumped out in the same situation, on my w/cache, as like 
+      on D. Weinehalls' Model 56, having integrated SCSI. This gave me the 
+      descissive hint to move the code-part out and declare it global. Now,
+      it seems to work by far much better an more stable. Let us see, what
+      the world thinks of it...
+   3) By the way, only Sony DAT-drives seem to show density code 0x13. A
+      test with a HP drive gave right results, so the problem is vendor-
+      specific and not a problem of the OS or the driver.
+   - Michael Lang
+   
+   Feb 18, 1999 (v3.1d)
+   1) The abort command and the reset function have been checked for 
+      inconsistencies. From the logical point of thinking, they work
+      at their optimum, now, but as the subsystem does not answer with an
+      interrupt, abort never finishes, sigh...
+   2) Everything, that is accessed by a busmaster request from the adapter
+      is now declared as global variable, even the return-buffer in the
+      local checking phase. This assures, that no accesses to undefined memory
+      areas are performed.
+   3) In ibmmca.h, the line unchecked_isa_dma is added with 1 in order to
+      avoid memory-pointers for the areas higher than 16MByte in order to
+      be sure, it also works on 16-Bit Microchannel bus systems.
+   4) A lot of small things have been found, but nothing that endangered the
+      driver operations. Just it should be more stable, now.
+   - Michael Lang
+      
+   Feb 20, 1999 (v3.1e)
+   1) I took the warning from the Linux Kernel Hackers Guide serious and 
+      checked the cmd->result return value to the done-function very carefuly.
+      It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if
+      some error appeared, else it is undefined. Now, this is fixed. Before
+      any SCB command gets queued, the tsb.dev_status is set to 0, so the 
+      cmd->result won't screw up Linux higher level drivers.
+   2) The reset-function has slightly improved. This is still planed for 
+      abort. During the abort and the reset function, no interrupts are 
+      allowed. This is however quite hard to cope with, so the INT-status
+      register is read. When the interrupt gets queued, one can find its
+      status immediately on that register and is enabled to continue in the
+      reset function. I had no chance to test this really, only in a bogus 
+      situation, I got this function running, but the situation was too much
+      worse for Linux :-(, so tests will continue.
+   3) Buffers got now consistent. No open address mapping, as before and
+      therefore no further troubles with the unassigned memory segmentation
+      faults that scrambled probes on 95XX series and even on 85XX series,
+      when the kernel is done in a not so perfectly fitting way.
+   4) Spontaneous interrupts from the subsystem, appearing without any
+      command previously queued are answered with a DID_BAD_INTR result.
+   5) Taken into account ZP Gus' proposals to reverse the SCSI-device
+      scan order. As it does not work on Kernel 2.1.x or 2.2.x, as proposed
+      by him, I implemented it in a slightly derived way, which offers in 
+      addition more flexibility.
+   - Michael Lang
+
+   4 To do
+   -------
+	- It seems that the handling of bad disks is really bad -
+	  non-existent, in fact.
+        - More testing of the full driver-controlled dynamical ldn 
+          (re)mapping for up to 56 SCSI-devices.
+        - Support more of the SCSI-command set.
+	- Support some of the caching abilities, particularly Read Prefetch.
+	  This fetches data into the cache, which later gets hit by the
+	  regular Read Data. (<--- This is coming soon!!!!)
+        - Abort and Reset functions still slightly buggy or better say,
+	  it is the new episode, called SCREAM III.
+
+   5 Users' Manual
+   ---------------
+   5.1 Commandline Parameters
+   --------------------------
+   There exist several features for the IBM SCSI-subsystem driver.
+   The commandline parameter format is:
+   
+         ibmmcascsi=<command1>,<command2>,<command3>,...
+	 
+   where commandN can be one of the following:
+   
+         display    Owners of a model 95 or other PS/2 systems with an
+	            alphanumeric LED display may set this to have their
+		    display showing the following output of the 8 digits:
+		      
+		                ------DA
+				
+		    where '-' stays dark, 'D' shows the SCSI-device id
+		    and 'A' shows the SCSI hostindex, beeing currently 
+		    accessed.
+	 adisplay   This works like display, but gives more optical overview 
+	            of the activities on the SCSI-bus. The display will have
+		    the following output:
+		    
+		                6543210A
+				
+		    where the numbers 0 to 6 light up at the shown position,
+		    when the SCSI-device is accessed. A shows again the SCSI
+		    hostindex. If display nor adisplay is set, the internal
+		    PS/2 harddisk LED is used for media-activities. So, if
+		    you really do not have a system with a LED-display, you
+		    should not set display or adisplay.
+	 bypass     This commandline parameter forces the driver never to use
+	            SCSI-subsystems' integrated SCSI-command set. Except of
+		    the immediate assign, which is of vital importance for
+		    every IBM SCSI-subsystem to set its ldns right. Instead,
+		    the ordinary ANSI-SCSI-commands are used and passed by the
+		    controller to the SCSI-devices, therefore 'bypass'. The
+		    effort, done by the subsystem is quite bogus and at a
+		    minimum and therefore it should work everywhere. This
+		    could maybe solve troubles with old or integrated SCSI-
+		    controllers and nasty harddisks. Keep in mind, that using 
+		    this flag will slow-down SCSI-accesses slightly, as the 
+		    software generated commands are always slower than the 
+		    hardware. Non-harddisk devices always get read/write-
+		    commands in bypass mode.
+	 normal     This is the parameter, introduced on the 2.0.x development
+	            rail by ZP Gu. This parameter defines the SCSI-device
+		    scan order in the new industry standard. This means, that
+		    the first SCSI-device is the one with the lowest pun.
+		    E.g. harddisk at pun=0 is scanned before harddisk at
+		    pun=6, which means, that harddisk at pun=0 gets sda
+		    and the one at pun=6 gets sdb.
+	 ansi       The ANSI-standard for the right scan order, as done by
+	            IBM, Microware and Microsoft, scans SCSI-devices starting
+		    at the highest pun, which means, that e.g. harddisk at
+		    pun=6 gets sda and a harddisk at pun=0 gets sdb. If you
+		    like to have the same SCSI-device order, as in DOS, OS-9
+		    or OS/2, just use this parameter.
+		    
+   A further option is that you can force the SCSI-driver to accept a SCSI-
+   subsystem at a certain I/O-address with a predefined adapter PUN. This
+   is done by entering 
+
+                  commandN   = I/O-base
+		  commandN+1 = adapter PUN
+		  
+   e.g. ibmmcascsi=0x3540,7 will force the driver to detect a SCSI-subsystem 
+   at I/O-address 0x3540 with adapter PUN 7.
+   
+   Examples:
+   
+        ibmmcascsi=adisplay,bypass
+	
+   This will use the advanced display mode for the model 95 LED display and
+   every SCSI-command passed to a attached device will get bypassed in order
+   not to use any of the subsystem built-in commands.
+   
+        ibmmcascsi=display,0x3558,7
+	
+   This will activate the default display mode for the model 95 LED display
+   and will force the driver to accept a SCSI-subsystem at I/O-base 0x3558
+   with adapter PUN 7.
+   
+   5.2 Troubleshooting
+   -------------------
+   The following FAQs should help you to solve some major problems with this
+   driver.
+   
+     Q: "Reset SCSI-devices at boottime" halts the system at boottime, why?
+     A: This is only tested with the IBM SCSI Adapter w/cache. It is not
+        yet prooved to run on other adapters, however you may be lucky.
+	In version 3.1d this has been hugely improved and should work better,
+	now. Normally you really won't need to activate this flag in the
+	kernel configuration, as all post 1989 SCSI-devices should accept
+	the reset-signal, when the computer is switched on. The SCSI-
+	subsystem generates this reset while beeing initialized. This flag
+	is really reserved for users with very old, very strange or self-made
+	SCSI-devices.
+     Q: Why is the SCSI-order of my drives mirrored to the device-order
+        seen from OS/2 or DOS ?
+     A: It depends on the operating system, if it looks at the devices in
+        ANSI-SCSI-standard (starting from pun 6 and going down to pun 0) or
+	if it just starts at pun 0 and counts up. If you want to be conform
+	with OS/2 and DOS, you have to activate this flag in the kernel
+	configuration or you should set 'ansi' as parameter for the kernel.
+	The parameter 'normal' sets the new industry standard, starting
+	from pun 0, scaning up to pun 6. This allows you to change your 
+	opinion still after having already compiled the kernel.
+     Q: Why can I not find the IBM MCA SCSI support in the config menue?
+     A: You have to activate MCA bus support, first.
+     Q: Where can I find the latest info about this driver?
+     A: See the file MAINTAINERS for the current WWW-address, which offers
+        updates, info and Q/A lists. At this files' origin, the webaddress
+	was: http://www.uni-mainz.de/~langm000/linux.html
+     Q: My SCSI-adapter is not recognized by the driver, what can I do?
+     A: Just force it to be recognized by kernel parameters. See section 5.1.
+     Q: The driver screws up, if it starts to probe SCSI-devices, is there
+        some way out of it?
+     A: This is based on some problems with the driver. In such cases, send
+        e-mail to the maintainer. If you are owner of a model with the serial
+	number 95XX, just send as subject NOTIFY 95XX PROBLEM and the 
+	maintainer immediately knows about your problem. But please:
+	Check your hardware and only if it works fine with other operating
+	systems, send E-Mail to me to notify the troubles. See the homepage
+	for how to send bug-reports or please read the next Q/A, here:
+     Q: I get a message: panic IBM MCA SCSI: command error .... , what can
+        I do against this?
+     A: Previously, I followed the way by ignoring command errors by using
+        ibmmcascsi=forgiveall, but this command no longer exists and is
+	obsolete. If such a problem appears, it is caused by some segmentation
+	fault of the driver, which maps to some unallowed area. The latest 
+	version of the driver should be ok, as most bugs have been solved.
+     Q: There are still kernel panics, even after having set 
+        ibmmcascsi=forgiveall. Are there other possibilities to prevent
+	such panics?
+     A: No, get just the latest release of the driver and it should work 
+        better and better with increasing version number. Forget this
+	ibmmcascsi=forgiveall, as also ignorecmd are obsolete.
+     Q: Linux panics or stops without any comment, but it is probable, that my
+        harddisk(s) have bad blocks.
+     A: Sorry, the bad-block handling is still a feeble point of this driver,
+        but is on the schedule for development in the near future.
+     Q: Linux panics while dynamically assigning SCSI-ids or ldns.
+     A: If you disconnect a SCSI-device from the machine, while Linux is up
+        and the driver uses dynamical reassignment of logical device numbers
+	(ldn), it really gets "angry" if it won't find devices, that were still
+	present at boottime and stops Linux.
+     Q: The system does not recover after an abort-command has been generated.
+     A: This is regrettably true, as it is not yet understood, why the 
+        SCSI-adapter does really NOT generate any interrupt at the end of
+	the abort-command. As no interrupt is generated, the abort command
+	cannot get finished and the system hangs, sorry, but checks are 
+	running to hunt down this problem. If there is a real pending command,
+	the interrupt MUST get generated after abort. In this case, it
+	should finish well.
+     Q: The system gets in bad shape after a SCSI-reset, is this known?
+     A: Yes, as there are a lot of prescriptions (see the Linux Hackers'
+        Guide) what has to be done for reset, we still share the bad shape of
+	the reset functions with all other low level SCSI-drivers. 
+	Astonishingly, reset works in most cases quite ok, but the harddisks
+	won't run in synchonous mode anymore after a reset, until you reboot.
+     Q: Why does my XXX w/Cache adapter not use read-prefetch?
+     A: w/Cache technical manuals are incoming here, so if I understood the
+        command of read-prefetch, it should be an easy thing to get harddisks
+	read in read-prefetch with w/Cache controllers. Some weeks or months,
+	still ahead and a lot of work still to do, sigh ...
+	
+   5.3 Bugreports
+   --------------
+   If you really find bugs in the sourcecode or the driver will successfully
+   refuse to work on your machine, you should send a bug report to me. The
+   best for this is to follow the instructions on the WWW-page for this
+   driver. Fill out the bug-report form, placed on the WWW-page and ship it,
+   so the bugs can be taken into account with maximum efforts. But, please
+   do not send bug reports about this driver to Linus Torvalds or Leonard
+   Zubkoff, as Linus is burried in E-Mail and Leonard is supervising all
+   SCSI-drivers and won't have the time left to look inside every single
+   driver to fix a bug and especially DO NOT send modified code to Linus
+   Torvalds, which has not been checked here!!! Recently, I got a lot of 
+   bugreports for errors in the ibmmca.c code, which I could not imagine, but
+   a look inside some Linux-distribution showed me quite often some modified
+   code, which did no longer work on most other machines than the one of the
+   modifier. Ok, so now that there is maintenance service available for this
+   driver, please use this address first in order to keep the level of
+   confusion low. Thank you!
+   
+   When you get a SCSI-error message that panics your system, a list of
+   register-entries of the SCSI-subsystem is shown (from Version 3.1d). With 
+   this list, it is very easy for the maintainer to localize the problem in 
+   the driver or in the configuration of the user. Please write down all the 
+   values from this report and send them to the maintainer. This would really 
+   help a lot and makes life easier concerning misunderstandings.
+   
+   Use the bug-report form (see 5.4 for its address) to send all the bug-
+   stuff to the maintainer or write e-mail with the values from the table. 
+   
+   5.4 Support WWW-page
+   --------------------
+   The address of the IBM SCSI-subsystem supporting WWW-page is:
+   
+        http://www.uni-mainz.de/~langm000/linux.html
+	
+   Here you can find info about the background of this driver, patches,
+   news and a bugreport form.
+   
+   6 References
+   ------------
+   The source of information is "Update for the PS/2 Hardware 
+   Interface Technical Reference, Common Interfaces", September 1991, 
+   part number 04G3281, available in the U.S. for $21.75 at 
+   1-800-IBM-PCTB, elsewhere call your local friendly IBM 
+   representative. E.g. in Germany, "Hallo IBM" works really great.
+   In addition to SCSI subsystem, this update contains fairly detailed 
+   (at hardware register level) sections on diskette  controller,
+   keyboard controller, serial port controller, VGA, and XGA.
+  
+   Additional information from "Personal System/2 Micro Channel SCSI
+   Adapter with Cache Technical Reference", March 1990, PN 68X2365,
+   probably available from the same source (or possibly found buried
+   in officemates desk).
+ 
+   Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
+   Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
+   Addison Wesley, 1996.
+   
+   Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel
+   Hill - North Carolina, 1995
+   
+   Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart
+   1993
+   
+   Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme *
+   Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988
+   
+   7 Trademarks
+   ------------
+   IBM, PS/2, OS/2, Microchannel are registered trademarks of International 
+   Business Machines Corp.
+   
+   MS-DOS is a registered trademark of Microsoft Corporation
+   
+   OS-9 is a registered trademark of Microware Systems
+   
+------
+Michael Lang 
+(lan...@kph.uni-mainz.de)
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.2.7/linux/drivers/scsi/ibmmca.c	Thu Dec 31 10:29:01 1998
+++ linux/drivers/scsi/ibmmca.c	Mon May 10 13:00:10 1999
@@ -3,291 +3,30 @@
X  *
X  * Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU 
X  * General Public License. Written by Martin Kolinek, December 1995.
+ * Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang
+ * See the file README.ibmmca for a detailed description of this driver,
+ * the commandline arguments and the history of its development.
+ * See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
+ * updates and info.
X  */
X 
-/* Update history:
-   Jan 15 1996:  First public release.
-   - Martin Kolinek
-
-   Jan 23 1996:  Scrapped code which reassigned scsi devices to logical
-   device numbers. Instead, the existing assignment (created
-   when the machine is powered-up or rebooted) is used. 
-   A side effect is that the upper layer of Linux SCSI 
-   device driver gets bogus scsi ids (this is benign), 
-   and also the hard disks are ordered under Linux the 
-   same way as they are under dos (i.e., C: disk is sda, 
-   D: disk is sdb, etc.).
-   - Martin Kolinek
-
-   I think that the CD-ROM is now detected only if a CD is 
-   inside CD_ROM while Linux boots. This can be fixed later,
-   once the driver works on all types of PS/2's.
-   - Martin Kolinek
-
-   Feb 7 1996:   Modified biosparam function. Fixed the CD-ROM detection. 
-   For now, devices other than harddisk and CD_ROM are 
-   ignored. Temporarily modified abort() function 
-   to behave like reset().
-   - Martin Kolinek
-
-   Mar 31 1996:  The integrated scsi subsystem is correctly found
-   in PS/2 models 56,57, but not in model 76. Therefore
-   the ibmmca_scsi_setup() function has been added today.
-   This function allows the user to force detection of
-   scsi subsystem. The kernel option has format
-   ibmmcascsi=n
-   where n is the scsi_id (pun) of the subsystem. Most likely, n is 7.
-   - Martin Kolinek
-
-   Aug 21 1996:  Modified the code which maps ldns to (pun,0).  It was
-   insufficient for those of us with CD-ROM changers.
-   - Chris Beauregard
- 
-   Dec 14 1996: More improvements to the ldn mapping.  See check_devices
-   for details.  Did more fiddling with the integrated SCSI detection,
-   but I think it's ultimately hopeless without actually testing the
-   model of the machine.  The 56, 57, 76 and 95 (ultimedia) all have
-   different integrated SCSI register configurations.  However, the 56
-   and 57 are the only ones that have problems with forced detection.
-   - Chris Beauregard
- 
-   Mar 8-16 1997: Modified driver to run as a module and to support 
-   multiple adapters. A structure, called ibmmca_hostdata, is now
-   present, containing all the variables, that were once only
-   available for one single adapter. The find_subsystem-routine has vanished.
-   The hardware recognition is now done in ibmmca_detect directly.
-   This routine checks for presence of MCA-bus, checks the interrupt
-   level and continues with checking the installed hardware.
-   Certain PS/2-models do not recognize a SCSI-subsystem automatically.
-   Hence, the setup defined by command-line-parameters is checked first.
-   Thereafter, the routine probes for an integrated SCSI-subsystem.
-   Finally, adapters are checked. This method has the advantage to cover all
-   possible combinations of multiple SCSI-subsystems on one MCA-board. Up to
-   eight SCSI-subsystems can be recognized and announced to the upper-level
-   drivers with this improvement. A set of defines made changes to other
-   routines as small as possible.
-   - Klaus Kudielka
-   
-   May 30 1997: (v1.5b)
-   1) SCSI-command capability enlarged by the recognition of MODE_SELECT.
-      This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which 
-      allows data to be written from the system to the device. It is a
-      necessary step to be allowed to set blocksize of SCSI-tape-drives and 
-      the tape-speed, whithout confusing the SCSI-Subsystem.
-   2) The recognition of a tape is included in the check_devices routine.
-      This is done by checking for TYPE_TAPE, that is already defined in
-      the kernel-scsi-environment. The markup of a tape is done in the 
-      global ldn_is_tape[] array. If the entry on index ldn 
-      is 1, there is a tapedrive connected.
-   3) The ldn_is_tape[] array is necessary to distinguish between tape- and 
-      other devices. Fixed blocklength devices should not cause a problem
-      with the SCB-command for read and write in the ibmmca_queuecommand
-      subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for
-      the tape-devices, as recommended by IBM in this Technical Reference,
-      mentioned below. (IBM recommends to avoid using the read/write of the
-      subsystem, but the fact was, that read/write causes a command error from
-      the subsystem and this causes kernel-panic.)
-   4) In addition, I propose to use the ldn instead of a fix char for the
-      display of PS2_DISK_LED_ON(). On 95, one can distinguish between the
-      devices that are accessed. It shows activity and easyfies debugging.   
-   The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2
-   (I do not know yet the type). Optimization and CD-ROM audio-support, 
-   I am working on ...
-   - Michael Lang
-   
-   June 19 1997: (v1.6b)
-   1) Submitting the extra-array ldn_is_tape[] -> to the local ld[]
-      device-array. 
-   2) CD-ROM Audio-Play seems to work now.
-   3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code
-      0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears 
-      also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that 
-      the problem is independent of the low-level-driver/bus-architecture.
-   4) Hexadecimal ldn on PS/2-95 LED-display.
-   5) Fixing of the PS/2-LED on/off that it works right with tapedrives and
-      does not confuse the disk_rw_in_progress counter.
-   - Michael Lang
-  
-   June 21 1997: (v1.7b)
-   1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/<host> the
-      outer-world about operational load statistics on the different ldns,
-      seen by the driver. Everybody that has more than one IBM-SCSI should
-      test this, because I only have one and cannot see what happens with more
-      than one IBM-SCSI hosts.
-   2) Definition of a driver version-number to have a better recognition of 
-      the source when there are existing too much releases that may confuse
-      the user, when reading about release-specific problems. Up to know,
-      I calculated the version-number to be 1.7. Because we are in BETA-test
-      yet, it is today 1.7b.
-   3) Sorry for the heavy bug I programmed on June 19 1997! After that, the
-      CD-ROM did not work any more! The C7-command was a fake impression
-      I got while programming. Now, the READ and WRITE commands for CD-ROM are
-      no longer running over the subsystem, but just over 
-      IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts
-      much faster(!) and hopefully all fancy multimedia-functions, like direct
-      digital recording from audio-CDs also work. (I tried it with cdda2wav
-      from the cdwtools-package and it filled up the harddisk immediately :-).)
-      To easify boolean logics, a further local device-type in ld[], called
-      is_cdrom has been included.
-   4) If one uses a SCSI-device of unsupported type/commands, one
-      immediately runs into a kernel-panic caused by Command Error. To better
-      understand which SCSI-command caused the problem, I extended this
-      specific panic-message slightly.
-   - Michael Lang
- 
-   June 25 1997: (v1.8b)
-   1) Some cosmetical changes for the handling of SCSI-device-types.
-      Now, also CD-Burners / WORMs and SCSI-scanners should work. For
-      MO-drives I have no experience, therefore not yet supported.
-      In logical_devices I changed from different type-variables to one
-      called 'device_type' where the values, corresponding to scsi.h,
-      of a SCSI-device are stored.
-   2) There existed a small bug, that maps a device, coming after a SCSI-tape
-      wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong
-      -> problem removed.
-   3) Extension of the logical_device structure. Now it contains also device,
-      vendor and revision-level of a SCSI-device for internal usage.
-   - Michael Lang
-
-   June 26-29 1997: (v2.0b)
-   1) The release number 2.0b is necessary because of the completely new done
-      recognition and handling of SCSI-devices with the adapter. As I got
-      from Chris the hint, that the subsystem can reassign ldns dynamically,
-      I remembered this immediate_assign-command, I found once in the handbook.
-      Now, the driver first kills all ldn assignments that are set by default
-      on the SCSI-subsystem. After that, it probes on all puns and luns for
-      devices by going through all combinations with immediate_assign and
-      probing for devices, using device_inquiry. The found physical(!) pun,lun
-      structure is stored in get_scsi[][] as device types. This is followed
-      by the assignment of all ldns to existing SCSI-devices. If more ldns
-      than devices are available, they are assigned to non existing pun,lun
-      combinations to satisfy the adapter. With this, the dynamical mapping
-      was possible to implement. (For further info see the text in the 
-      source-code and in the description below. Read the description
-      below BEFORE installing this driver on your system!)
-   2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION.
-   3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID
-      (pun) of the accessed SCSI-device. This is now senseful, because the 
-      pun known within the driver is exactly the pun of the physical device
-      and no longer a fake one.
-   4) The /proc/scsi/ibmmca/<host_no> consists now of the first part, where
-      hit-statistics of ldns is shown and a second part, where the maps of 
-      physical and logical SCSI-devices are displayed. This could be very 
-      interesting, when one is using more than 15 SCSI-devices in order to 
-      follow the dynamical remapping of ldns.
-   - Michael Lang
- 
-   June 26-29 1997: (v2.0b-1)
-   1) I forgot to switch the local_checking_phase_flag to 1 and back to 0
-      in the dynamical remapping part in ibmmca_queuecommand for the 
-      device_exist routine. Sorry.
-   - Michael Lang
- 
-   July 1-13 1997: (v3.0b,c)
-   1) Merging of the driver-developments of Klaus Kudielka and Michael Lang 
-      in order to get a optimum and unified driver-release for the 
-      IBM-SCSI-Subsystem-Adapter(s).
-         For people, using the Kernel-release >=2.1.0, module-support should 
-      be no problem. For users, running under <2.1.0, module-support may not 
-      work, because the methods have changed between 2.0.x and 2.1.x.
-   2) Added some more effective statistics for /proc-output.
-   3) Change typecasting at necessary points from (unsigned long) to
-      virt_to_bus().
-   4) Included #if... at special points to have specific adaption of the
-      driver to kernel 2.0.x and 2.1.x. It should therefore also run with 
-      later releases.
-   5) Magneto-Optical drives and medium-changers are also recognized, now.
-      Therefore, we have a completely gapfree recognition of all SCSI-
-      device-types, that are known by Linux up to kernel 2.1.31.
-   6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within
-      the configuration, each connected SCSI-device will get a reset command
-      during boottime. This can be necessary for some special SCSI-devices.
-      This flag should be included in Config.in.
-      (See also the new Config.in file.)
-   Probable next improvement: bad disk handler.
-   - Michael Lang
- 
-   Sept 14 1997: (v3.0c)
-   1) Some debugging and speed optimization applied.
-   - Michael Lang
-
-   Dec 15, 1997
-    - chr...@truespectra.com
-    - made the front panel display thingy optional, specified from the
-    command-line via ibmmcascsi=display.  Along the lines of the /LED
-    option for the OS/2 driver.
-    - fixed small bug in the LED display that would hang some machines.
-    - reversed ordering of the drives (using the
-    IBMMCA_SCSI_ORDER_STANDARD define).  This is necessary for two main
-    reasons:
-	- users who've already installed Linux won't be screwed.  Keep
-	in mind that not everyone is a kernel hacker.
-	- be consistent with the BIOS ordering of the drives.  In the
-	BIOS, id 6 is C:, id 0 might be D:.  With this scheme, they'd be
-	backwards.  This confuses the crap out of those heathens who've
-	got a impure Linux installation (which, <wince>, I'm one of).
-    This whole problem arises because IBM is actually non-standard with
-    the id to BIOS mappings.  You'll find, in fdomain.c, a similar
-    comment about a few FD BIOS revisions.  The Linux (and apparently
-    industry) standard is that C: maps to scsi id (0,0).  Let's stick
-    with that standard.
-    - Since this is technically a branch of my own, I changed the
-    version number to 3.0e-cpb.
-
-   Jan 17, 1998: (v3.0f)
-   1) Addition of some statistical info for /proc in proc_info.
-   2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15
-      1997. In fact, IBM is right, concerning the assignment of SCSI-devices 
-      to driveletters. It is conform to the ANSI-definition of the SCSI-
-      standard to assign drive C: to SCSI-id 6, because it is the highest
-      hardware priority after the hostadapter (that has still today by
-      default everywhere id 7). Also realtime-operating systems that I use, 
-      like LynxOS and OS9, which are quite industrial systems use top-down
-      numbering of the harddisks, that is also starting at id 6. Now, one
-      sits a bit between two chairs. On one hand side, using the define
-      IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to
-      the IBM- and ANSI-SCSI-standard and keeps this driver downward
-      compatible to older releases, on the other hand side, people is quite
-      habituated in believing that C: is assigned to (0,0) and much other
-      SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD 
-      define out of the driver and put it into Config.in as subitem of 
-      'IBM SCSI support'. A help, added to Documentation/Configure.help 
-      explains the differences between saying 'y' or 'n' to the user, when 
-      IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to 
-      choose the way of assignment, depending on his own situation and gusto.
-   3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is
-      now called IBMMCA_SCSI_DEV_RESET.
-   4) Optimization of proc_info and its subroutines.
-   5) Added more in-source-comments and extended the driver description by
-      some explanation about the SCSI-device-assignment problem.
-   - Michael Lang
-   
-   Jan 18, 1998: (v3.0g)
-   1) Correcting names to be absolutely conform to the later 2.1.x releases.
-      This is necessary for 
-            IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET
-            IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   - Michael Lang
-
-	TODO:
- 
-	- It seems that the handling of bad disks is really bad -
-	  non-existent, in fact.
-        - More testing of the full driver-controlled dynamical ldn 
-          (re)mapping for up to 56 SCSI-devices.
-        - Support more SCSI-device-types, if Linux defines more.
-        - Support more of the SCSI-command set.
-	- Support some of the caching abilities, particularly Read Prefetch.
-	  This fetches data into the cache, which later gets hit by the
-	  regular Read Data.
-        - Abort and Reset functions still slightly buggy. Especially when
-          floppydisk(!) operations report errors.
+/******************* HEADER FILE INCLUDES ************************************/
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
X 
-******************************************************************************/
+/* choose adaption for Kernellevel */
+#define local_LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#if LINUX_VERSION_CODE < local_LinuxVersionCode(2,1,0)
+#define OLDKERN
+#else
+#undef OLDKERN
+#endif
X 
X #include <linux/module.h>
X #include <linux/kernel.h>
X #include <linux/types.h>
+#include <linux/ctype.h>
X #include <linux/string.h>
X #include <linux/ioport.h>
X #include <linux/delay.h>
@@ -297,7 +36,9 @@
X #include <linux/stat.h>
X #include <linux/mca.h>
X #include <asm/system.h>
+#ifndef OLDKERN
X #include <asm/spinlock.h>
+#endif
X #include <asm/io.h>
X #include "sd.h"
X #include "scsi.h"
@@ -306,199 +47,29 @@
X 
X #include <linux/config.h>		/* for CONFIG_SCSI_IBMMCA etc. */
X 
-/*--------------------------------------------------------------------*/
-
-/* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "3.0f"
-
-/* use standard Linux ordering, where C: maps to (0,0), unlike the IBM
-standard which seems to like C: => (6,0) */
-/* #define IBMMCA_SCSI_ORDER_STANDARD is defined/undefined in Config.in
- * now, while configuring the kernel. */
+/******************* LOCAL DEFINES *******************************************/
X 
-/*
-   Driver Description
-
-   (A) Subsystem Detection
-   This is done in the ibmmca_detect() function and is easy, since
-   the information about MCA integrated subsystems and plug-in 
-   adapters is readily available in structure *mca_info.
-
-   (B) Physical Units, Logical Units, and Logical Devices
-   There can be up to 56 devices on SCSI bus (besides the adapter):
-   there are up to 7 "physical units" (each identified by physical unit 
-   number or pun, also called the scsi id, this is the number you select
-   with hardware jumpers), and each physical unit can have up to 8 
-   "logical units" (each identified by logical unit number, or lun, 
-   between 0 and 7). 
-
-   Typically the adapter has pun=7, so puns of other physical units
-   are between 0 and 6. Almost all physical units have only one   
-   logical unit, with lun=0. A CD-ROM jukebox would be an example of 
-   a physical unit with more than one logical unit.
-
-   The embedded microprocessor of IBM SCSI subsystem hides the complex
-   two-dimensional (pun,lun) organization from the operating system.
-   When the machine is powered-up (or rebooted, I am not sure), the 
-   embedded microprocessor checks, on it own, all 56 possible (pun,lun) 
-   combinations, and first 15 devices found are assigned into a 
-   one-dimensional array of so-called "logical devices", identified by 
-   "logical device numbers" or ldn. The last ldn=15 is reserved for 
-   the subsystem itself. 
-
-   One consequence of information hiding is that the real (pun,lun)    
-   numbers are also hidden. Therefore this driver takes the following
-   approach: It checks the ldn's (0 to 6) to find out which ldn's
-   have devices assigned. This is done by function check_devices() and
-   device_exists(). The interrupt handler has a special paragraph of code
-   (see local_checking_phase_flag) to assist in the checking. Assume, for
-   example, that three logical devices were found assigned at ldn 0, 1, 2.
-   These are presented to the upper layer of Linux SCSI driver
-   as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0). 
-   On the other hand, if the upper layer issues a command to device
-   say (4,0), this driver returns DID_NO_CONNECT error.
-
-   That last paragraph is no longer correct, but is left for
-   historical purposes.  It limited the number of devices to 7, far
-   fewer than the 15 that it could use.  Now it just maps
-   ldn -> (ldn/8,ldn%8).  We end up with a real mishmash of puns
-   and luns, but it all seems to work. - Chris Beaurgard
-
-   And that last paragraph is also no longer correct.  It uses a
-   slightly more complex mapping that will always map hard disks to
-   (x,0), for some x, and consecutive none disk devices will usually
-   share puns.
- 
-   Again, the last paragraphs are no longer correct. Now, the physical
-   SCSI-devices on the SCSI-bus are probed via immediate_assign- and
-   device_inquiry-commands. This delivers a exact map of the physical
-   SCSI-world that is now stored in the get_scsi[][]-array. This means,
-   that the once hidden pun,lun assignment is now known to this driver.
-   It no longer believes in default-settings of the subsystem and maps all
-   ldns to existing pun,lun by foot. This assures full control of the ldn
-   mapping and allows dynamical remapping of ldns to different pun,lun, if
-   there are more SCSI-devices installed than ldns available (n>15). The
-   ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0,
-   excluding the pun of the subsystem. This assures, that at least simple 
-   SCSI-installations have optimum access-speed and are not touched by
-   dynamical remapping. The ldns 7 to 14 are put to existing devices with 
-   lun>0 or to non-existing devices, in order to satisfy the subsystem, if 
-   there are less than 15 SCSI-devices connected. In the case of more than 15 
-   devices, the dynamical mapping goes active. If the get_scsi[][] reports a 
-   device to be existant, but it has no ldn assigned, it gets a ldn out of 7 
-   to 14. The numbers are assigned in cyclic order. Therefore it takes 8 
-   dynamical assignments on SCSI-devices, until a certain device 
-   looses its ldn again. This assures, that dynamical remapping is avoided 
-   during intense I/O between up to eight SCSI-devices (means pun,lun 
-   combinations). A further advantage of this method is, that people who
-   build their kernel without probing on all luns will get what they expect.
- 
-   IMPORTANT: Because of the now correct recognition of physical pun,lun, and 
-   their report to mid-level- and higher-level-drivers, the new reported puns
-   can be different from the old, faked puns. Therefore, Linux will eventually
-   change /dev/sdXXX assignments and prompt you for corrupted superblock
-   repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
-   You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file
-   entries right. After that, the system should come up as errorfree as before.
-   If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
-   in a Linux session booted on old kernel and run lilo before reboot. Check
-   lilo.conf anyway to get boot on other partitions with foreign OSes right
-   again. 
- 
-   The problem is, that Linux does not assign the SCSI-devices in the
-   way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to 
-   the device with at minimum id 0. But the first drive should be at id 6,
-   because for historical reasons, drive at id 6 has, by hardware, the highest
-   priority and a drive at id 0 the lowest. IBM was one of the rare producers,
-   where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most 
-   other producers' BIOS does not (I think even Adaptec-BIOS). The 
-   IBMMCA_SCSI_ORDER_STANDARD flag helps to be able to choose the preferred 
-   way of SCSI-device-assignment. Defining this flag would result in Linux 
-   determining the devices in the same order as DOS and OS/2 does on your 
-   MCA-machine. This is also standard on most industrial computers. Leaving 
-   this flag undefined will get your devices ordered in the default way of 
-   Linux. See also the remarks of Chris Beauregard from Dec 15, 1997 and
-   the followups.
-   
-   (C) Regular Processing 
-   Only three functions get involved: ibmmca_queuecommand(), issue_cmd(),
-   and interrupt_handler().
-
-   The upper layer issues a scsi command by calling function 
-   ibmmca_queuecommand(). This function fills a "subsystem control block"
-   (scb) and calls a local function issue_cmd(), which writes a scb 
-   command into subsystem I/O ports. Once the scb command is carried out, 
-   interrupt_handler() is invoked. If a device is determined to be existant
-   and it has not assigned any ldn, it gets one dynamically.
-
-   (D) Abort, Reset.
-   These are implemented with busy waiting for interrupt to arrive.
-   The abort does not worked well for me, so I instead call the 
-   ibmmca_reset() from the ibmmca_abort() function.
-
-   (E) Disk Geometry
-   The ibmmca_biosparams() function should return same disk geometry 
-   as bios. This is needed for fdisk, etc. The returned geometry is 
-   certainly correct for disk smaller than 1 gigabyte, but I am not 
-   100% sure that it is correct for larger disks.
-
-   (F) Kernel Boot Option 
-   The function ibmmca_scsi_setup() is called if option ibmmcascsi=n 
-   is passed to the kernel. See file linux/init/main.c for details.
-   
-   (G) Driver Module Support
-   Is implemented and tested by K. Kudielka. This could probably not work
-   on kernels <2.1.0.
-  
-   (H) Multiple Hostadapter Support
-   This driver supports up to eight interfaces of type IBM-SCSI-Subsystem. 
-   Integrated-, and MCA-adapters are automatically recognized. Unrecognizable
-   IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters.
- 
-   (I) /proc-Filesystem Information
-   Information about the driver condition is given in 
-   /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info provides this information.
- */
+#ifndef mdelay
+#define mdelay(a)    udelay((a) * 1000)
+#endif
X 
X /*--------------------------------------------------------------------*/
-/* Here are the values and structures specific for the subsystem. 
- * The source of information is "Update for the PS/2 Hardware 
- * Interface Technical Reference, Common Interfaces", September 1991, 
- * part number 04G3281, available in the U.S. for $21.75 at 
- * 1-800-IBM-PCTB, elsewhere call your local friendly IBM 
- * representative.
- * In addition to SCSI subsystem, this update contains fairly detailed 
- * (at hardware register level) sections on diskette  controller,
- * keyboard controller, serial port controller, VGA, and XGA.
- *
- * Additional information from "Personal System/2 Micro Channel SCSI
- * Adapter with Cache Technical Reference", March 1990, PN 68X2365,
- * probably available from the same source (or possibly found buried
- * in officemates desk).
- *
- * Further literature/program-sources referred for this driver:
- * 
- * Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
- * Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
- * Addison Wesley, 1996.
- * 
- * Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel
- * Hill - North Carolina, 1995
- * 
- * Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart
- * 1993
- */
+
+/* current version of this driver-source: */
+#define IBMMCA_SCSI_DRIVER_VERSION "3.1e"
X 
X /*--------------------------------------------------------------------*/
X 
X /* driver configuration */
X #define IM_MAX_HOSTS      8             /* maximum number of host adapters */
-#define IM_RESET_DELAY    10            /* seconds allowed for a reset */
+#define IM_RESET_DELAY    60            /* seconds allowed for a reset */
X 
X /* driver debugging - #undef all for normal operation */
X 
X /* if defined: count interrupts and ignore this special one: */
X #undef  IM_DEBUG_TIMEOUT  50            
+#define TIMEOUT_PUN   0
+#define TIMEOUT_LUN   0
X /* verbose interrupt: */
X #undef  IM_DEBUG_INT                   
X /* verbose queuecommand: */
@@ -512,11 +83,11 @@
X #define IM_DEBUG_CMD_DEVICE   TYPE_TAPE
X 
X /* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG   (shpnt->io_port)   /*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG  (shpnt->io_port+4) /*Attention (1 byte) */
-#define IM_CTR_REG   (shpnt->io_port+5) /*Basic Control (1 byte) */
-#define IM_INTR_REG  (shpnt->io_port+6) /*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG  (shpnt->io_port+7) /*Basic Status (1 byte, read only) */
+#define IM_CMD_REG(hi)   (hosts[(hi)]->io_port)   /*Command Interface, (4 bytes long) */
+#define IM_ATTN_REG(hi)  (hosts[(hi)]->io_port+4) /*Attention (1 byte) */
+#define IM_CTR_REG(hi)   (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */
+#define IM_INTR_REG(hi)  (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */
+#define IM_STAT_REG(hi)  (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */
X 
X /* basic I/O-port of first adapter */
X #define IM_IO_PORT   0x3540
@@ -668,9 +239,15 @@
X 
X /* use_display is set by the ibmmcascsi=display command line arg */
X static int use_display = 0;
+/* use_adisplay is set by ibmmcascsi=adisplay, which offers a higher
+ * level of displayed luxus on PS/2 95 (really fancy! :-))) */
+static int use_adisplay = 0;
+
X #define PS2_DISK_LED_ON(ad,id) {\
X 	if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \
X         outb((char)(ad+48), MOD95_LED_PORT+1); } \
+        else if( use_adisplay ) { if (id<7) outb((char)(id+48), \
+	MOD95_LED_PORT+1+id); outb((char)(ad+48), MOD95_LED_PORT); } \
X 	else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
X }
X 
@@ -678,6 +255,11 @@
X #define PS2_DISK_LED_OFF() {\
X 	if( use_display ) { outb( ' ', MOD95_LED_PORT ); \
X         outb(' ', MOD95_LED_PORT+1); } \
+        if ( use_adisplay ) { outb(' ',MOD95_LED_PORT ); \
+	outb(' ',MOD95_LED_PORT+1); outb(' ',MOD95_LED_PORT+2); \
+        outb(' ',MOD95_LED_PORT+3); outb(' ',MOD95_LED_PORT+4); \
+        outb(' ',MOD95_LED_PORT+5); outb(' ',MOD95_LED_PORT+6); \
+	outb(' ',MOD95_LED_PORT+7); } \
X 	else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
X }
X 
@@ -693,18 +275,20 @@
X /* List of possible IBM-SCSI-adapters */
X struct subsys_list_struct subsys_list[] =
X {
-  {0x8efc, "IBM Fast SCSI-2 Adapter"},
-  {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"},
-  {0x8ef8, "IBM Expansion Unit SCSI Controller"},
-  {0x8eff, "IBM SCSI Adapter w/Cache"},
-  {0x8efe, "IBM SCSI Adapter"},
-};
+  {0x8efc, "IBM Fast SCSI-2 Adapter"}, /* special = 0 */
+  {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"}, /* special = 1 */
+  {0x8ef8, "IBM Expansion Unit SCSI Controller"},/* special = 2 */
+  {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */
+  {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */
+};                   
X 
X /*for /proc filesystem */
X struct proc_dir_entry proc_scsi_ibmmca =
X {
X   PROC_SCSI_IBMMCA, 6, "ibmmca",
-  S_IFDIR | S_IRUGO | S_IXUGO, 2
+  S_IFDIR | S_IRUGO | S_IXUGO, 2,
+  0, 0, 0, NULL, NULL, NULL, NULL,
+  NULL, NULL, NULL 
X };
X 
X /* Max number of logical devices (can be up from 0 to 14).  15 is the address
@@ -715,8 +299,9 @@
X struct logical_device
X   {
X     struct im_scb scb; /* SCSI-subsystem-control-block structure */
-    struct im_tsb tsb;
-    struct im_sge sge[16];
+    struct im_tsb tsb; /* SCSI command complete status block structure */
+    struct im_sge sge[16]; /* scatter gather list structure */
+    unsigned char buf[256]; /* SCSI command return data buffer */
X     Scsi_Cmnd *cmd;  /* SCSI-command that is currently in progress */
X      
X     int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
@@ -736,6 +321,7 @@
X       int total_accesses;                    /* total accesses on all ldns */
X       int total_interrupts;                  /* total interrupts (should be
X 						same as total_accesses) */
+      int total_errors;                      /* command completed with error */
X       /* dynamical assignment statistics */
X       int total_scsi_devices;                /* number of physical pun,lun */
X       int dyn_flag;                          /* flag showing dynamical mode */
@@ -747,44 +333,54 @@
X /* data structure for each host adapter */
X struct ibmmca_hostdata
X {
-  /* array of logical devices: */
-    struct logical_device _ld[MAX_LOG_DEV];   
-  /* array to convert (pun, lun) into logical device number: */
-    unsigned char _get_ldn[8][8];
-  /*array that contains the information about the physical SCSI-devices
-   attached to this host adapter: */
-    unsigned char _get_scsi[8][8];
-  /* used only when checking logical devices: */
-    int _local_checking_phase_flag;
-  /* report received interrupt: */
-    int _got_interrupt;
-  /* report termination-status of SCSI-command: */
-    int _stat_result;
-  /* reset status (used only when doing reset): */
-    int _reset_status;
-  /* code of the last SCSI command (needed for panic info): */
-    int _last_scsi_command;
-  /* Counter that points on the next reassignable ldn for dynamical 
-   remapping. The default value is 7, that is the first reassignable 
-   number in the list at boottime: */
-    int _next_ldn;
-  /* Statistics-structure for this IBM-SCSI-host: */
-    struct Driver_Statistics _IBM_DS;
+   /* array of logical devices: */
+   struct logical_device _ld[MAX_LOG_DEV+1];   
+   /* array to convert (pun, lun) into logical device number: */
+   unsigned char _get_ldn[8][8];
+   /*array that contains the information about the physical SCSI-devices
+    attached to this host adapter: */
+   unsigned char _get_scsi[8][8];
+   /* used only when checking logical devices: */
+   int _local_checking_phase_flag;
+   /* report received interrupt: */
+   int _got_interrupt;
+   /* report termination-status of SCSI-command: */
+   int _stat_result;
+   /* reset status (used only when doing reset): */
+   int _reset_status;
+   /* code of the last SCSI command (needed for panic info): */
+   int _last_scsi_command[MAX_LOG_DEV+1];
+   /* identifier of the last SCSI-command type */
+   int _last_scsi_type[MAX_LOG_DEV+1];
+   /* Counter that points on the next reassignable ldn for dynamical 
+    remapping. The default value is 7, that is the first reassignable 
+    number in the list at boottime: */
+   int _next_ldn;
+   /* Statistics-structure for this IBM-SCSI-host: */
+   struct Driver_Statistics _IBM_DS;
+   /* This hostadapters pos-registers pos2 and pos3 */
+   unsigned _pos2, _pos3;
+   /* assign a special variable, that contains dedicated info about the
+    adaptertype */
+   int _special;
X };
X 
X /* macros to access host data structure */
-#define HOSTDATA(shpnt) ((struct ibmmca_hostdata *) shpnt->hostdata)
-#define subsystem_pun (shpnt->this_id)
-#define ld (HOSTDATA(shpnt)->_ld)
-#define get_ldn (HOSTDATA(shpnt)->_get_ldn)
-#define get_scsi (HOSTDATA(shpnt)->_get_scsi)
-#define local_checking_phase_flag (HOSTDATA(shpnt)->_local_checking_phase_flag)
-#define got_interrupt (HOSTDATA(shpnt)->_got_interrupt)
-#define stat_result (HOSTDATA(shpnt)->_stat_result)
-#define reset_status (HOSTDATA(shpnt)->_reset_status)
-#define last_scsi_command (HOSTDATA(shpnt)->_last_scsi_command)
-#define next_ldn (HOSTDATA(shpnt)->_next_ldn)
-#define IBM_DS (HOSTDATA(shpnt)->_IBM_DS)
+#define subsystem_pun(hi) (hosts[(hi)]->this_id)
+#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
+#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
+#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
+#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)
+#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)
+#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)
+#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
+#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
+#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
+#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
+#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
+#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
+#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos2)
+#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos3)
X 
X /* Define a arbitrary number as subsystem-marker-type. This number is, as 
X    described in the ANSI-SCSI-standard, not occupied by other device-types. */
@@ -805,11 +401,23 @@
X #define SET_LDN        0
X #define REMOVE_LDN     1
X 
+/* ldn which is used to probe the SCSI devices */
+#define PROBE_LDN      0
+
X /* reset status flag contents */
-#define IM_RESET_NOT_IN_PROGRESS   0
-#define IM_RESET_IN_PROGRESS       1
-#define IM_RESET_FINISHED_OK       2
-#define IM_RESET_FINISHED_FAIL     3
+#define IM_RESET_NOT_IN_PROGRESS         0
+#define IM_RESET_IN_PROGRESS             1
+#define IM_RESET_FINISHED_OK             2
+#define IM_RESET_FINISHED_FAIL           3
+#define IM_RESET_NOT_IN_PROGRESS_NO_INT  4
+#define IM_RESET_FINISHED_OK_NO_INT      5
+
+/* special flags for hostdata structure */
+#define FORCED_DETECTION         100
+#define INTEGRATED_SCSI          101
+
+/* define undefined SCSI-command */
+#define NO_SCSI                  0xffff
X 
X /*-----------------------------------------------------------------------*/
X 
@@ -823,277 +431,517 @@
X MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
X MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); 
X MODULE_PARM(display, "1i");
+MODULE_PARM(adisplay, "1i");
+MODULE_PARM(bypass, "1i");
+MODULE_PARM(normal, "1i");
+MODULE_PARM(ansi, "1i");
X #endif
X 
X /*counter of concurrent disk read/writes, to turn on/off disk led */
X static int disk_rw_in_progress = 0;
X 
+/* spinlock handling to avoid command clash while in operation */
+#ifndef OLDKERN
+spinlock_t info_lock  = SPIN_LOCK_UNLOCKED;
+spinlock_t proc_lock  = SPIN_LOCK_UNLOCKED;
+spinlock_t abort_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t issue_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t intr_lock  = SPIN_LOCK_UNLOCKED;
+#endif
+
X /* host information */
X static int found = 0;
X static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL };
+static unsigned int pos[8]; /* whole pos register-line */
+/* Taking into account the additions, made by ZP Gu.
+ * This selects now the preset value from the configfile and
+ * offers the 'normal' commandline option to be accepted */
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+static char ibm_ansi_order = 1;
+#else
+static char ibm_ansi_order = 0;
+#endif
+
X /*-----------------------------------------------------------------------*/
X 
-/*local functions in forward declaration */
-static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static void issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, 
-                       unsigned char attn_reg);
+/******************* FUNCTIONS IN FORWARD DECLARATION ************************/
+
+static void interrupt_handler (int, void *, struct pt_regs *);
+#ifndef OLDKERN
+static void do_interrupt_handler (int, void *, struct pt_regs *);
+#endif
+static void issue_cmd (int, unsigned long, unsigned char);
X static void internal_done (Scsi_Cmnd * cmd);
-static void check_devices (struct Scsi_Host *shpnt);
-static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, 
-                            unsigned int lun, unsigned int ldn, 
-                            unsigned int operation);
-static int device_inquiry(struct Scsi_Host *shpnt, int ldn, 
-                          unsigned char *buf);
-static char *ti_p(int value);
-static char *ti_l(int value);
-static int device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length,
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 18'
echo 'File patch-2.2.8 is continued in part 19'
echo 19 > _shar_seq_.tmp
#!/bin/sh
# this is part 19 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 19; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
-                          int *device_type);
-static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * template, 
-					 int port, int id);
+static void check_devices (int);
+static int immediate_assign(int, unsigned int, unsigned int, unsigned int, 
+                            unsigned int);
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+static int immediate_reset(int, unsigned int);
+#endif
+static int device_inquiry(int, int);
+static int read_capacity(int, int);
+static char *ti_p(int);
+static char *ti_l(int);
+static int device_exists (int, int, int *, int *);
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, 
+					 int, int, char *);
X 
X /* local functions needed for proc_info */
-static int ldn_access_load(struct Scsi_Host *shpnt, int ldn);
-static int ldn_access_total_read_write(struct Scsi_Host *shpnt);
+static int ldn_access_load(int, int);
+static int ldn_access_total_read_write(int);
X 
+static int bypass_controller = 0;   /* bypass integrated SCSI-cmd set flag */
X /*--------------------------------------------------------------------*/
X 
-static void 
-do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+/******************* LOCAL FUNCTIONS IMPLEMENTATION *************************/
+
+#ifndef OLDKERN
+/* newer Kernels need the spinlock interrupt handler */
+static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
X {
X   unsigned long flags;
X 
X   spin_lock_irqsave(&io_request_lock, flags);
X   interrupt_handler(irq, dev_id, regs);
X   spin_unlock_irqrestore(&io_request_lock, flags);
+  return; 
X }
+#endif
X 
-static void 
-interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
X {
-  int i = 0;
-  struct Scsi_Host *shpnt;
-  unsigned int intr_reg;
-  unsigned int cmd_result;
-  unsigned int ldn;
-  unsigned long flags;
+   int host_index;
+   unsigned int intr_reg;
+   unsigned int cmd_result;
+   unsigned int ldn;
+   static unsigned long flags;
+   Scsi_Cmnd *cmd;
+   int errorflag;
+   int interror;
X 
-  /* search for one adapter-response on shared interrupt */
-  do
-    shpnt = hosts[i++];
-  while (shpnt && !(inb(IM_STAT_REG) & IM_INTR_REQUEST));
-
-  /* return if some other device on this IRQ caused the interrupt */
-  if (!shpnt) return;
-
-  /*get command result and logical device */
-  intr_reg = inb (IM_INTR_REG);
-  cmd_result = intr_reg & 0xf0;
-  ldn = intr_reg & 0x0f;
-
-  /*must wait for attention reg not busy, then send EOI to subsystem */
-  save_flags(flags);
-  while (1) {
-      cli ();
-      if (!(inb (IM_STAT_REG) & IM_BUSY)) 
-        break;
-      restore_flags(flags);
-    }
-  outb (IM_EOI | ldn, IM_ATTN_REG);
-  restore_flags (flags);
-
-  /*these should never happen (hw fails, or a local programming bug) */
-  if (cmd_result == IM_ADAPTER_HW_FAILURE)
-    panic ("IBM MCA SCSI: subsystem hardware failure. Last SCSI_CMD=0x%X. \n",
-	   last_scsi_command);
-  if (cmd_result == IM_CMD_ERROR)
-    panic ("IBM MCA SCSI: command error. Last SCSI_CMD=0x%X. \n",
-	   last_scsi_command);
-  if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR)
-    panic ("IBM MCA SCSI: software sequencing error. Last SCSI_CMD=0x%X. \n",
-	   last_scsi_command);
-
-  /* if no panic appeared, increase the interrupt-counter */
-  IBM_DS.total_interrupts++;
-   
-  /*only for local checking phase */
-  if (local_checking_phase_flag)
-    {
-      stat_result = cmd_result;
-      got_interrupt = 1;
-      reset_status = IM_RESET_FINISHED_OK;
-      return;
-    }
-
-  /*handling of commands coming from upper level of scsi driver */
-  else
-    {
-      Scsi_Cmnd *cmd;
-
-      /*verify ldn, and may handle rare reset immediate command */
-      if (ldn >= MAX_LOG_DEV)
-	{
-	  if (ldn == 0xf && reset_status == IM_RESET_IN_PROGRESS)
-	    {
-	      if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-		{
-		  reset_status = IM_RESET_FINISHED_FAIL;
-		}
-	      else
-		{
-		  /*reset disk led counter, turn off disk led */
-		  disk_rw_in_progress = 0;
-		  PS2_DISK_LED_OFF ();
-		  reset_status = IM_RESET_FINISHED_OK;
-		}
-	      return;
-	    }
-	  else
-	    panic ("IBM MCA SCSI: invalid logical device number.\n");
-	}
+   host_index=0; /* make sure, host_index is 0, else this won't work and
+		    never dare to ask, what happens, if an interrupt-handler
+		    does not work :-((( .... */
+   
+   /* search for one adapter-response on shared interrupt */
+   while (hosts[host_index]
+	  && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST))
+     host_index++;
+   
+   /* return if some other device on this IRQ caused the interrupt */
+   if (!hosts[host_index]) return;
X 
-#ifdef IM_DEBUG_TIMEOUT
-      {
-        static int count = 0;
+   /* the reset-function already did all the job, even ints got
+      renabled on the subsystem, so just return */
+   if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)||
+       (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT))
+     {
+	reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
+	return;
+     }
+   
+   /*get command result and logical device */
+   intr_reg = inb (IM_INTR_REG(host_index));
+   cmd_result = intr_reg & 0xf0;
+   ldn = intr_reg & 0x0f;
X 
-        if (++count == IM_DEBUG_TIMEOUT) {
-          printk("IBM MCA SCSI: Ignoring interrupt.\n");
-          return;
-        }
-      }
+   /*must wait for attention reg not busy, then send EOI to subsystem */
+   while (1) 
+     {
+#ifdef OLDKERN
+	save_flags(flags);
+	cli();
+#else
+	spin_lock_irqsave(&intr_lock, flags);
+#endif	
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) 
+	  break;
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&intr_lock, flags);
X #endif
+     }
+   outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+   /* get the last_scsi_command here */
+   interror = last_scsi_command(host_index)[ldn];   
+#ifdef OLDKERN
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&intr_lock, flags);
+#endif      
+   errorflag = 0; /* no errors by default */   
+   /*these should never happen (hw fails, or a local programming bug) */
+   if (cmd_result == IM_ADAPTER_HW_FAILURE)
+     {
+	printk("\n");
+	printk("IBM MCA SCSI: ERROR - subsystem hardware failure!\n");
+	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
+	       last_scsi_command(host_index)[ldn],ldn,host_index);
+	errorflag = 1;
+     }
+   if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR)
+     {
+	printk("\n");
+	printk("IBM MCA SCSI: ERROR - software sequencing error!\n");
+	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
+	       last_scsi_command(host_index)[ldn],ldn,host_index);
+	errorflag = 1;	
+     }
+   if (cmd_result == IM_CMD_ERROR)
+     {
+	printk("\n");
+	printk("IBM MCA SCSI: ERROR - command error!\n");
+	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
+	       last_scsi_command(host_index)[ldn],ldn,host_index);
+	errorflag = 1;	
+     }
+   if (errorflag)
+     { /* if errors appear, enter this section to give detailed info */
+	printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
+	printk("              Command Type................: %x\n",
+	       last_scsi_type(host_index)[ldn]);
+	printk("              Attention Register..........: %x\n",
+	       inb (IM_ATTN_REG(host_index)));
+        printk("              Basic Control Register......: %x\n",
+	       inb (IM_CTR_REG(host_index)));
+	printk("              Interrupt Status Register...: %x\n",
+	       intr_reg);
+	printk("              Basic Status Register.......: %x\n",
+	       inb (IM_STAT_REG(host_index)));
+	if ((last_scsi_type(host_index)[ldn]==IM_SCB)||
+	    (last_scsi_type(host_index)[ldn]==IM_LONG_SCB))
+	  {
+	     printk("              SCB End Status Word.........: %x\n",
+		    ld(host_index)[ldn].tsb.end_status);
+	     printk("              Command Status..............: %x\n",
+		    ld(host_index)[ldn].tsb.cmd_status);
+	     printk("              Device Status...............: %x\n",
+		    ld(host_index)[ldn].tsb.dev_status);
+	     printk("              Command Error...............: %x\n",
+		    ld(host_index)[ldn].tsb.cmd_error);
+	     printk("              Device Error................: %x\n",
+		    ld(host_index)[ldn].tsb.dev_error);
+	     printk("              Last SCB Address (LSW)......: %x\n",
+		    ld(host_index)[ldn].tsb.low_of_last_scb_adr);
+	     printk("              Last SCB Address (MSW)......: %x\n",
+		    ld(host_index)[ldn].tsb.high_of_last_scb_adr);
+	  }
+	printk("              Send report to the maintainer.\n");
+	panic("IBM MCA SCSI: Fatal errormessage from the subsystem!\n");
+     }
+   
+   /* if no panic appeared, increase the interrupt-counter */
+   IBM_DS(host_index).total_interrupts++;
X 
-      /*if no command structure, just return, else clear cmd */
-      cmd = ld[ldn].cmd;
-      if (!cmd)
+   /*only for local checking phase */
+   if (local_checking_phase_flag(host_index))
+     {
+	stat_result(host_index) = cmd_result;
+	got_interrupt(host_index) = 1;
+	reset_status(host_index) = IM_RESET_FINISHED_OK;
+	last_scsi_command(host_index)[ldn] = NO_SCSI;
X 	return;
-      ld[ldn].cmd = 0;
-
+     }   
+   /*handling of commands coming from upper level of scsi driver */
+   else
+     {
+	if (last_scsi_type(host_index)[ldn] == IM_IMM_CMD)
+	  {
+	     /*verify ldn, and may handle rare reset immediate command */
+	     if ((reset_status(host_index) == IM_RESET_IN_PROGRESS)&&
+		 (last_scsi_command(host_index)[ldn] == IM_RESET_IMM_CMD))
+	       {
+		  if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+		    {
+		       disk_rw_in_progress = 0;
+		       PS2_DISK_LED_OFF ();
+		       reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+		    }
+		  else
+		    {
+		       /*reset disk led counter, turn off disk led */
+		       disk_rw_in_progress = 0;
+		       PS2_DISK_LED_OFF ();
+		       reset_status(host_index) = IM_RESET_FINISHED_OK;
+		    }
+		  stat_result(host_index) = cmd_result;
+		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  return;
+	       }
+	     else if (last_scsi_command(host_index)[ldn] == IM_ABORT_IMM_CMD)
+	       { /* react on SCSI abort command */
+#ifdef IM_DEBUG_PROBE
+		  printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
+#endif	
+		  disk_rw_in_progress = 0;
+		  PS2_DISK_LED_OFF();
+		  cmd = ld(host_index)[ldn].cmd;
+		  if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+		    cmd->result = DID_NO_CONNECT << 16;
+		  else
+		    cmd->result = DID_ABORT << 16;
+		  stat_result(host_index) = cmd_result;
+		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  if (cmd->scsi_done)
+		    (cmd->scsi_done) (cmd); /* should be the internal_done */
+		  return;
+	       }
+	     else
+	       {
+		  disk_rw_in_progress = 0;
+		  PS2_DISK_LED_OFF ();
+		  reset_status(host_index) = IM_RESET_FINISHED_OK;
+		  stat_result(host_index) = cmd_result;
+		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  return;
+	       }	     
+	  }
+	last_scsi_command(host_index)[ldn] = NO_SCSI;	     
+	cmd = ld(host_index)[ldn].cmd;
+#ifdef IM_DEBUG_TIMEOUT
+	if (cmd)
+	  {
+	     if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN))
+	       {
+		  printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n",
+			 cmd->target, cmd->lun);
+		  return;
+	       }
+	  }
+#endif
+	/*if no command structure, just return, else clear cmd */
+	if (!cmd)
+	  return;
+	ld(host_index)[ldn].cmd = NULL;
+	
X #ifdef IM_DEBUG_INT
-      printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", 
-         cmd->cmnd[0], intr_reg, 
-         ld[ldn].tsb.dev_status, ld[ldn].tsb.cmd_status, 
-         ld[ldn].tsb.dev_error, ld[ldn].tsb.cmd_error); 
-#endif
-
-      /*if this is end of media read/write, may turn off PS/2 disk led */
-      if ((ld[ldn].device_type!=TYPE_NO_LUN)&&
-	  (ld[ldn].device_type!=TYPE_NO_DEVICE))
-	{ /* only access this, if there was a valid device addressed */
-	  switch (cmd->cmnd[0])
-	    {
-	    case READ_6:
-	    case WRITE_6:
-	    case READ_10:
-	    case WRITE_10:
-	    case READ_12:
-	    case WRITE_12:
-	      if (--disk_rw_in_progress == 0)
-		PS2_DISK_LED_OFF ();
-	    }
-	}
-       
-      /*write device status into cmd->result, and call done function */
-      if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-	cmd->result = ld[ldn].tsb.dev_status & 0x1e;
-      else
-	cmd->result = 0;
-      (cmd->scsi_done) (cmd);
-    }
-}
-
-/*--------------------------------------------------------------------*/
-
-static void 
-issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, 
-           unsigned char attn_reg)
-{
-  unsigned long flags;
-  /*must wait for attention reg not busy */
-  save_flags(flags);
-  while (1)
-    {
-      cli ();
-      if (!(inb (IM_STAT_REG) & IM_BUSY))
-	break;
-      restore_flags (flags);
-    }
+	printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", 
+	       cmd->cmnd[0], intr_reg, 
+	       ld(host_index)[ldn].tsb.dev_status, 
+	       ld(host_index)[ldn].tsb.cmd_status,
+	       ld(host_index)[ldn].tsb.dev_error, 
+	       ld(host_index)[ldn].tsb.cmd_error);
+#endif
+	
+	/*if this is end of media read/write, may turn off PS/2 disk led */
+	if ((ld(host_index)[ldn].device_type!=TYPE_NO_LUN)&&
+	    (ld(host_index)[ldn].device_type!=TYPE_NO_DEVICE))
+	  { /* only access this, if there was a valid device addressed */
+	     switch (cmd->cmnd[0])
+	       {
+		case READ_6:
+		case WRITE_6:
+		case READ_10:
+		case WRITE_10:
+		case READ_12:
+		case WRITE_12:
+		  if (--disk_rw_in_progress == 0)
+		    PS2_DISK_LED_OFF ();
+	       }
+	  }
X 
-  /*write registers and enable system interrupts */
-  outl (cmd_reg, IM_CMD_REG);
-  outb (attn_reg, IM_ATTN_REG);
-  restore_flags (flags);
+	/* IBM describes the status-mask to be 0x1e, but this is not conform
+	 * with SCSI-defintion, I suppose, it is a printing error in the
+	 * technical reference and assume as mask 0x3e. (ML) */
+	cmd->result = (ld(host_index)[ldn].tsb.dev_status & 0x3e);
+	/* write device status into cmd->result, and call done function */
+	if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+	  IBM_DS(host_index).total_errors++;
+	if (interror == NO_SCSI) /* unexpected interrupt :-( */
+	  cmd->result |= DID_BAD_INTR << 16;
+	else
+	  cmd->result |= DID_OK << 16;
+	(cmd->scsi_done) (cmd);
+     }
+   if (interror == NO_SCSI)
+     printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
+   return;
X }
X 
X /*--------------------------------------------------------------------*/
X 
-static void 
-internal_done (Scsi_Cmnd * cmd)
+static void issue_cmd (int host_index, unsigned long cmd_reg, 
+		       unsigned char attn_reg)
X {
-  cmd->SCp.Status++;
+   static unsigned long flags;
+   /* must wait for attention reg not busy */   
+   while (1)
+     {
+#ifdef OLDKERN	
+	save_flags(flags);
+	cli();
+#else
+	spin_lock_irqsave(&issue_lock, flags);
+#endif	
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	  break;
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&issue_lock, flags);
+#endif	
+     }
+   /*write registers and enable system interrupts */
+   outl (cmd_reg, IM_CMD_REG(host_index));
+   outb (attn_reg, IM_ATTN_REG(host_index));
+#ifdef OLDKERN   
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&issue_lock, flags);
+#endif
X }
X 
X /*--------------------------------------------------------------------*/
X 
-static int ibmmca_getinfo (char *buf, int slot, void *dev)
+static void internal_done (Scsi_Cmnd * cmd)
X {
-  struct Scsi_Host *shpnt = dev;
-  int len = 0;
-
-  len += sprintf (buf + len, "Subsystem PUN: %d\n", subsystem_pun);
-  len += sprintf (buf + len, "I/O base address: 0x%lx\n", IM_CMD_REG);
-  return len;
+   cmd->SCp.Status++;
X }
X 
X /*--------------------------------------------------------------------*/
X 
X /* SCSI-SCB-command for device_inquiry */
-static int device_inquiry(struct Scsi_Host *shpnt, int ldn, unsigned char *buf)
+static int device_inquiry(int host_index, int ldn)
X {   
-  struct im_scb scb;
-  struct im_tsb tsb;
-  int retries;
-
-  for (retries = 0; retries < 3; retries++)
-    {
-      /*fill scb with inquiry command */
-      scb.command = IM_DEVICE_INQUIRY_CMD;
-      scb.enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-      scb.sys_buf_adr = virt_to_bus(buf);
-      scb.sys_buf_length = 255;
-      scb.tsb_adr = virt_to_bus(&tsb);
-
-      /*issue scb to passed ldn, and busy wait for interrupt */
-      got_interrupt = 0;
-      issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn);
-      while (!got_interrupt)
-	barrier ();
-
-      /*if command succesful, break */
-      if (stat_result == IM_SCB_CMD_COMPLETED)
-	break;
-    }
+   int retries;
+   Scsi_Cmnd cmd;
+   struct im_scb *scb;
+   struct im_tsb *tsb;
+   unsigned char *buf;
+   
+   scb = &(ld(host_index)[ldn].scb);
+   tsb = &(ld(host_index)[ldn].tsb);
+   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
+   ld(host_index)[ldn].tsb.dev_status = 0; /* prepare stusblock */
+
+   if (bypass_controller)
+     { /* fill the commonly known field for device-inquiry SCSI cmnd */
+	cmd.cmd_len = 6;
+        memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len);
+	cmd.cmnd[0] = INQUIRY; /* device inquiry */
+	cmd.cmnd[4] = 0xff; /* return buffer size = 255 */
+     }   
+   for (retries = 0; retries < 3; retries++)
+     {
+	if (bypass_controller)
+	  { /* bypass the hardware integrated command set */
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;      
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; 
+	     scb->u1.scsi_cmd_length = cmd.cmd_len;
+	     memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
+	     last_scsi_command(host_index)[ldn] = INQUIRY;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;
+	  }
+	else
+	  {
+	     /*fill scb with inquiry command */
+	     scb->command = IM_DEVICE_INQUIRY_CMD;
+	     scb->enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;	     
+	  }
+	scb->sys_buf_adr = virt_to_bus(buf);
+	scb->sys_buf_length = 0xff; /* maximum bufferlength gives max info */
+	scb->tsb_adr = virt_to_bus(tsb);
+	
+	/*issue scb to passed ldn, and busy wait for interrupt */
+	got_interrupt(host_index) = 0;
+	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	while (!got_interrupt(host_index))
+	  barrier ();
+	
+	/*if command succesful, break */
+	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
+	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+	  {
+	     return 1;
+	  }
+     }
+   
+   /*if all three retries failed, return "no device at this ldn" */
+   if (retries >= 3)
+     return 0;
+   else
+     return 1;
+}
X 
-  /*if all three retries failed, return "no device at this ldn" */
-  if (retries >= 3)
-    return 0;
-  else
-    return 1;
+static int read_capacity(int host_index, int ldn)
+{
+   int retries;
+   Scsi_Cmnd cmd;
+   struct im_scb *scb;
+   struct im_tsb *tsb;
+   unsigned char *buf;
+   
+   scb = &(ld(host_index)[ldn].scb);
+   tsb = &(ld(host_index)[ldn].tsb);
+   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
+   ld(host_index)[ldn].tsb.dev_status = 0;
+   
+   if (bypass_controller)
+     { /* read capacity in commonly known default SCSI-format */
+	cmd.cmd_len = 10;
+        memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len);
+	cmd.cmnd[0] = READ_CAPACITY; /* read capacity */
+     }	
+   for (retries = 0; retries < 3; retries++)
+     {
+	/*fill scb with read capacity command */
+	if (bypass_controller)
+	  { /* bypass the SCSI-command */
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;      
+	     scb->enable |= IM_READ_CONTROL;
+	     scb->u1.scsi_cmd_length = cmd.cmd_len;
+	     memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
+	     last_scsi_command(host_index)[ldn] = READ_CAPACITY;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;
+	  }
+	else
+	  {
+	     scb->command = IM_READ_CAPACITY_CMD;
+	     scb->enable = IM_READ_CONTROL;
+	     last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;	     
+	  }
+	scb->sys_buf_adr = virt_to_bus(buf);
+	scb->sys_buf_length = 8;
+	scb->tsb_adr = virt_to_bus(tsb);
+	
+	/*issue scb to passed ldn, and busy wait for interrupt */
+	got_interrupt(host_index) = 0;
+	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	while (!got_interrupt(host_index))
+	  barrier ();
+	     
+	     /*if got capacity, get block length and return one device found */
+	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
+	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+	  {
+	     return 1;
+	  }
+     }
+   /*if all three retries failed, return "no device at this ldn" */
+   if (retries >= 3)
+     return 0;
+   else
+     return 1;
X }
X 
X /* SCSI-immediate-command for assign. This functions maps/unmaps specific
-   ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
-   subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, 
+ ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
+ subsystem and for dynamical remapping od ldns. */
+static int immediate_assign(int host_index, unsigned int pun, 
X                             unsigned int lun, unsigned int ldn, 
X                             unsigned int operation)
X {
X    int retries;
X    unsigned long imm_command;
-
+   
X    for (retries=0; retries<3; retries ++)
-     {	
-        imm_command = inl(IM_CMD_REG);
+     {
+        imm_command = inl(IM_CMD_REG(host_index));
X         imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */
X         imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD);
X         imm_command |= (unsigned long)((lun & 7) << 24);
@@ -1101,14 +949,64 @@
X         imm_command |= (unsigned long)((pun & 7) << 20);
X         imm_command |= (unsigned long)((ldn & 15) << 16);
X 	
-        got_interrupt = 0;
-        issue_cmd (shpnt, (unsigned long)(imm_command), IM_IMM_CMD | 0xf);
-        while (!got_interrupt)
-           barrier ();
-	       
+	last_scsi_command(host_index)[0xf] = IM_ASSIGN_IMM_CMD;
+	last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+        got_interrupt(host_index) = 0;
+        issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | 0xf);
+        while (!got_interrupt(host_index))
+	  barrier ();
+	
+        /*if command succesful, break */
+	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+	  {
+	     return 1;
+	  }
+     }
+   
+   if (retries >= 3) 
+     return 0;
+   else
+     return 1;
+}
+
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+static int immediate_reset(int host_index, unsigned int ldn)
+{
+   int retries;
+   int ticks;
+   unsigned long imm_command;
+   
+   for (retries=0; retries<3; retries ++)
+     {
+        imm_command = inl(IM_CMD_REG(host_index));
+        imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */
+        imm_command |= (unsigned long)(IM_RESET_IMM_CMD);
+	last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
+	last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+
+	got_interrupt(host_index) = 0;
+	reset_status(host_index) = IM_RESET_IN_PROGRESS;        
+	issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn);
+	ticks = IM_RESET_DELAY*HZ;	
+	while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) 
+	  {
+	     mdelay(1+999/HZ);
+	     barrier();
+	  }
+	/* if reset did not complete, just claim */
+	if (!ticks) 
+	  {
+	     printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
+		    IM_RESET_DELAY);
+	     reset_status(host_index) = IM_RESET_FINISHED_OK; 
+	     /* did not work, finish */
+	     return 1;
+	  }
X         /*if command succesful, break */
-        if (stat_result == IM_IMMEDIATE_CMD_COMPLETED)
-           break;
+	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+	  {
+	     return 1;
+	  }
X      }
X    
X    if (retries >= 3) 
@@ -1116,24 +1014,25 @@
X    else
X      return 1;
X }
+#endif
X 
X /* type-interpreter for physical device numbers */
X static char *ti_p(int value)
X {
X    switch (value)
X      {
-	case TYPE_IBM_SCSI_ADAPTER: return("A"); break;
-	case TYPE_DISK:             return("D"); break;
-	case TYPE_TAPE:             return("T"); break;
-	case TYPE_PROCESSOR:        return("P"); break;
-	case TYPE_WORM:             return("W"); break;
-	case TYPE_ROM:              return("R"); break;
-	case TYPE_SCANNER:          return("S"); break;
-	case TYPE_MOD:              return("M"); break;
-        case TYPE_MEDIUM_CHANGER:   return("C"); break;
-	case TYPE_NO_LUN:           return("+"); break; /* show NO_LUN */
-        case TYPE_NO_DEVICE:
-	default:                    return("-"); break;
+      case TYPE_IBM_SCSI_ADAPTER: return("A"); break;
+      case TYPE_DISK:             return("D"); break;
+      case TYPE_TAPE:             return("T"); break;
+      case TYPE_PROCESSOR:        return("P"); break;
+      case TYPE_WORM:             return("W"); break;
+      case TYPE_ROM:              return("R"); break;
+      case TYPE_SCANNER:          return("S"); break;
+      case TYPE_MOD:              return("M"); break;
+      case TYPE_MEDIUM_CHANGER:   return("C"); break;
+      case TYPE_NO_LUN:           return("+"); break; /* show NO_LUN */
+      case TYPE_NO_DEVICE:
+      default:                    return("-"); break;
X      }
X    return("-");
X }
@@ -1141,9 +1040,9 @@
X /* interpreter for logical device numbers (ldn) */
X static char *ti_l(int value)
X {
-   const char hex[16] = ("0123456789abcdef");
+   const char hex[16] = "0123456789abcdef";
X    static char answer[2];
-
+   
X    answer[1] = (char)(0x0);
X    if (value<=MAX_LOG_DEV)
X      answer[0] = hex[value];
@@ -1154,182 +1053,181 @@
X }
X 
X /* 
-   The following routine probes the SCSI-devices in four steps:
-   1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter.
-   2. ldn 0 is used to go through all possible combinations of pun,lun and
-      a device_inquiry is done to fiddle out whether there is a device
-      responding or not. This physical map is stored in get_scsi[][].
-   3. The 15 available ldns (0-14) are mapped to existing pun,lun.
-      If there are more devices than ldns, it stops at 14 for the boot
-      time. Dynamical remapping will be done in ibmmca_queuecommand.
-   4. If there are less than 15 valid pun,lun, the remaining ldns are
-      mapped to NON-existing pun,lun to satisfy the adapter. Information
-      about pun,lun -> ldn is stored as before in get_ldn[][].
-   This method leads to the result, that the SCSI-pun,lun shown to Linux
-   mid-level- and higher-level-drivers is exactly corresponding to the
-   physical reality on the SCSI-bus. Therefore, it is possible that users
-   of older releases of this driver have to rewrite their fstab-file, because
-   the /dev/sdXXX could have changed due to the right pun,lun report, now.
-   The assignment of ALL ldns avoids dynamical remapping by the adapter
-   itself.
+ The following routine probes the SCSI-devices in four steps:
+ 1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter.
+ 2. ldn 0 is used to go through all possible combinations of pun,lun and
+ a device_inquiry is done to fiddle out whether there is a device
+ responding or not. This physical map is stored in get_scsi[][].
+ 3. The 15 available ldns (0-14) are mapped to existing pun,lun.
+ If there are more devices than ldns, it stops at 14 for the boot
+ time. Dynamical remapping will be done in ibmmca_queuecommand.
+ 4. If there are less than 15 valid pun,lun, the remaining ldns are
+ mapped to NON-existing pun,lun to satisfy the adapter. Information
+ about pun,lun -> ldn is stored as before in get_ldn[][].
+ This method leads to the result, that the SCSI-pun,lun shown to Linux
+ mid-level- and higher-level-drivers is exactly corresponding to the
+ physical reality on the SCSI-bus. Therefore, it is possible that users
+ of older releases of this driver have to rewrite their fstab-file, because
+ the /dev/sdXXX could have changed due to the right pun,lun report, now.
+ The assignment of ALL ldns avoids dynamical remapping by the adapter
+ itself.
X  */
-static void check_devices (struct Scsi_Host *shpnt)
+static void check_devices (int host_index)
X {
-  int id, lun, ldn;
-  unsigned char buf[256];
-  int count_devices = 0; /* local counter for connected device */
-   
-  /* assign default values to certain variables */
-  
-  IBM_DS.dyn_flag = 0; /* normally no need for dynamical ldn management */
-  next_ldn = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
-  last_scsi_command = 0; /* emptify last SCSI-command storage */
-  
-  /* initialize the very important driver-informational arrays/structs */
-  memset (ld, 0, sizeof ld);
-  memset (get_ldn, TYPE_NO_DEVICE, sizeof get_ldn); /* this is essential ! */
-  memset (get_scsi, TYPE_NO_DEVICE, sizeof get_scsi); /* this is essential ! */
-
-  for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/
-    {
-      get_scsi[subsystem_pun][lun] = TYPE_IBM_SCSI_ADAPTER; 
-      get_ldn[subsystem_pun][lun] = MAX_LOG_DEV; /* make sure, the subsystem
-						    ldn is active for all
-						    luns. */
-    }
-
-  /* STEP 1: */
-  printk("IBM MCA SCSI: Removing current logical SCSI-device mapping.");
-  for (ldn=0; ldn<MAX_LOG_DEV; ldn++)
-    {
+   int id, lun, ldn, ticks;
+   int count_devices; /* local counter for connected device */
+   
+   /* assign default values to certain variables */
+
+   ticks = 0;
+   count_devices = 0;
+   IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
+   IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
+   next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
+   for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+     {
+	last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
+	last_scsi_type(host_index)[ldn] = 0;
+     }
+
+   /* initialize the very important driver-informational arrays/structs */
+   memset (ld(host_index), 0, 
+	   sizeof(ld(host_index)));
+   memset (get_ldn(host_index), TYPE_NO_DEVICE, 
+	   sizeof(get_ldn(host_index))); /* this is essential ! */
+   memset (get_scsi(host_index), TYPE_NO_DEVICE,
+	   sizeof(get_scsi(host_index))); /* this is essential ! */
+   
+   for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/
+     {
+	get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
+	get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
+								ldn is active for all
+								luns. */
+     }
+   
+   /* STEP 1: */
X #ifdef IM_DEBUG_PROBE
-      printk(".");
+   printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index);
X #endif
-      immediate_assign(shpnt,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/
-    }
-
-  lun = 0; /* default lun is 0 */
+   printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
+   for (ldn=0; ldn<MAX_LOG_DEV; ldn++)
+     {
+#ifdef IM_DEBUG_PROBE
+	printk(".");
+#endif
+	immediate_assign(host_index,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/
+     }
X 
-  /* STEP 2: */
-  printk("\nIBM MCA SCSI: Probing SCSI-devices.");
-  for (id=0; id<8; id++)
+   lun = 0; /* default lun is 0 */
+   
+   /* STEP 2: */
+   printk("\nIBM MCA SCSI: Probing SCSI-devices.");
+   for (id=0; id<8; id++)
X #ifdef CONFIG_SCSI_MULTI_LUN
-    for (lun=0; lun<8; lun++)
+     for (lun=0; lun<8; lun++)
X #endif
-      {
+     {
X #ifdef IM_DEBUG_PROBE
X 	printk(".");
X #endif
-	if (id != subsystem_pun) 
+	if (id != subsystem_pun(host_index))
X 	  {            /* if pun is not the adapter: */
-	    immediate_assign(shpnt,id,lun,0,SET_LDN); /*set ldn=0 to pun,lun*/
-	    if (device_inquiry(shpnt, 0, buf)) /* probe device */
-	      {
-		get_scsi[id][lun]=(unsigned char)buf[0];  /* entry, even 
-							     for NO_LUN */
-		if (buf[0] != TYPE_NO_LUN)
-		  count_devices++; /* a existing device is found */
-	      }
-	    immediate_assign(shpnt,id,lun,0,REMOVE_LDN); /* remove ldn */
+	     /*set ldn=0 to pun,lun*/
+	     immediate_assign(host_index,id,lun,PROBE_LDN,SET_LDN); 
+	     if (device_inquiry(host_index, PROBE_LDN)) /* probe device */
+	       {
+		  get_scsi(host_index)[id][lun]=
+		    (unsigned char)(ld(host_index)[PROBE_LDN].buf[0]);
+		  /* entry, even for NO_LUN */
+		  if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
+		    count_devices++; /* a existing device is found */
+	       }
+	     /* remove ldn */
+	     immediate_assign(host_index,id,lun,PROBE_LDN,REMOVE_LDN); 
X 	  }
-      }
-  
-  /* STEP 3: */   
-  printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
+     }
+   
+   /* STEP 3: */   
+   printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
+   
+   ldn = 0;
+   lun = 0;
X    
-  ldn = 0;
-  lun = 0;
-
X #ifdef CONFIG_SCSI_MULTI_LUN   
-  for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
+   for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
X #endif
-    for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
-      {
+     for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
+     {
X #ifdef IM_DEBUG_PROBE
X 	printk(".");
X #endif
-	if (id != subsystem_pun)
+	if (id != subsystem_pun(host_index))
X 	  {
-	    if (get_scsi[id][lun] != TYPE_NO_LUN && 
-		get_scsi[id][lun] != TYPE_NO_DEVICE)
-	      {
-		/* Only map if accepted type. Always enter for 
+	     if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN && 
+		 get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE)
+	       {
+		  /* Only map if accepted type. Always enter for 
X 		   lun == 0 to get no gaps into ldn-mapping for ldn<7. */
-		immediate_assign(shpnt,id,lun,ldn,SET_LDN);
-		get_ldn[id][lun]=ldn; /* map ldn */
-		if (device_exists (shpnt, ldn, &ld[ldn].block_length,
-				   &ld[ldn].device_type))
-		  {
+		  immediate_assign(host_index,id,lun,ldn,SET_LDN);
+		  get_ldn(host_index)[id][lun]=ldn; /* map ldn */
+		  if (device_exists (host_index, ldn, 
+				     &ld(host_index)[ldn].block_length,
+				     &ld(host_index)[ldn].device_type))
+		    {
X #ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-		    int ticks;
-		    printk("(resetting)");
-		    ticks = IM_RESET_DELAY*HZ;
-		    reset_status = IM_RESET_IN_PROGRESS;
-		    issue_cmd (shpnt, IM_RESET_IMM_CMD, IM_IMM_CMD | ldn);
-		    while (reset_status == IM_RESET_IN_PROGRESS && --ticks) 
-		      {
-			mdelay(1+999/HZ);
-			barrier();
-		      }
-		    /* if reset did not complete, just claim */
-		    if (!ticks) 
-		       {
-		          printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
-			         IM_RESET_DELAY);
-		          reset_status = IM_RESET_FINISHED_OK; 
-			                       /* did not work, finish */
-		       }
-#endif
-		    ldn++;
-		  }
-		else
-		  {
-		    /* device vanished, probably because we don't know how to
-		     * handle it or because it has problems */
-		     if (lun > 0)
-		       {
-			  /* remove mapping */
-			  get_ldn[id][lun]=TYPE_NO_DEVICE;
-			  immediate_assign(shpnt,0,0,ldn,REMOVE_LDN);
-		       }
-		     else ldn++;
-		  }
-	      }
-	   else if (lun == 0)
-	      {
-		 /* map lun == 0, even if no device exists */
-		 immediate_assign(shpnt,id,lun,ldn,SET_LDN);
-		 get_ldn[id][lun]=ldn; /* map ldn */
-		 ldn++;
-	      }
+		       printk("resetting device at ldn=%x ... ",ldn);
+		       immediate_reset(host_index,ldn);
+#endif
+		       ldn++;
+		    }
+		  else
+		    {
+		       /* device vanished, probably because we don't know how to
+			* handle it or because it has problems */
+		       if (lun > 0)
+			 {
+			    /* remove mapping */
+			    get_ldn(host_index)[id][lun]=TYPE_NO_DEVICE;
+			    immediate_assign(host_index,0,0,ldn,REMOVE_LDN);
+			 }
+		       else ldn++;
+		    }
+	       }
+	     else if (lun == 0)
+	       {
+		  /* map lun == 0, even if no device exists */
+		  immediate_assign(host_index,id,lun,ldn,SET_LDN);
+		  get_ldn(host_index)[id][lun]=ldn; /* map ldn */
+		  ldn++;
+	       }
X 	  }	 
-      }
-
+     }
+   
X    /* STEP 4: */
X    
X    /* map remaining ldns to non-existing devices */
X    for (lun=1; lun<8 && ldn<MAX_LOG_DEV; lun++)
X      for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
X      {
-	if (get_scsi[id][lun] == TYPE_NO_LUN ||
-	    get_scsi[id][lun] == TYPE_NO_DEVICE)
+	if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN ||
+	    get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE)
X 	  {
X 	     /* Map remaining ldns only to NON-existing pun,lun
-	        combinations to make sure an inquiry will fail. 
-	        For MULTI_LUN, it is needed to avoid adapter autonome
-	        SCSI-remapping. */
-	     immediate_assign(shpnt,id,lun,ldn,SET_LDN);
-	     get_ldn[id][lun]=ldn;
+	      combinations to make sure an inquiry will fail. 
+	      For MULTI_LUN, it is needed to avoid adapter autonome
+	      SCSI-remapping. */
+	     immediate_assign(host_index,id,lun,ldn,SET_LDN);
+	     get_ldn(host_index)[id][lun]=ldn;
X 	     ldn++;
X 	  }
X      }	
-	
+   
X    printk("\n");
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   printk("IBM MCA SCSI: SCSI-access-order: IBM/ANSI.\n");
-#else
-   printk("IBM MCA SCSI: SCSI-access-order: Linux.\n");
-#endif
+   if (ibm_ansi_order)
+     printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
+   else
+     printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
X    
X #ifdef IM_DEBUG_PROBE
X    /* Show the physical and logical mapping during boot. */
@@ -1338,336 +1236,525 @@
X    printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
X    for (id=0; id<8; id++)
X      {
-        printk("%2d     %2s %2s %2s %2s %2s %2s %2s %2s",
-	       id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]), 
-	       ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]), 
-	       ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]), 
-	       ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
-
-	printk("       %2d     ",id);
+        printk("%2d     ",id);
+	for (lun=0; lun<8; lun++)
+	  printk("%2s ",ti_p(get_scsi(host_index)[id][lun]));
+	printk("      %2d     ",id);
X 	for (lun=0; lun<8; lun++)
-	  printk("%2s ",ti_l(get_ldn[id][lun]));
+	  printk("%2s ",ti_l(get_ldn(host_index)[id][lun]));
X 	printk("\n");
X      }
X #endif
-
+   
X    /* assign total number of found SCSI-devices to the statistics struct */
-   IBM_DS.total_scsi_devices = count_devices;
-    
+   IBM_DS(host_index).total_scsi_devices = count_devices;
+   
X    /* decide for output in /proc-filesystem, if the configuration of
-      SCSI-devices makes dynamical reassignment of devices necessary */
+    SCSI-devices makes dynamical reassignment of devices necessary */
X    if (count_devices>=MAX_LOG_DEV) 
-     IBM_DS.dyn_flag = 1; /* dynamical assignment is necessary */
+     IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */
X    else 
-     IBM_DS.dyn_flag = 0; /* dynamical assignment is not necessary */
-
+     IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */
+   
X    /* If no SCSI-devices are assigned, return 1 in order to cause message. */
X    if (ldn == 0)
-     printk("IBM MCA SCSI: Warning: No SCSI-devices found/assignable!\n");
-
-  /* reset the counters for statistics on the current adapter */
-  IBM_DS.total_accesses = 0;
-  IBM_DS.total_interrupts = 0;
-  IBM_DS.dynamical_assignments = 0;
-  memset (IBM_DS.ldn_access, 0x0, sizeof (IBM_DS.ldn_access));
-  memset (IBM_DS.ldn_read_access, 0x0, sizeof (IBM_DS.ldn_read_access));
-  memset (IBM_DS.ldn_write_access, 0x0, sizeof (IBM_DS.ldn_write_access));
-  memset (IBM_DS.ldn_inquiry_access, 0x0, sizeof (IBM_DS.ldn_inquiry_access));
-  memset (IBM_DS.ldn_modeselect_access, 0x0, sizeof (IBM_DS.ldn_modeselect_access));
-  memset (IBM_DS.ldn_assignments, 0x0, sizeof (IBM_DS.ldn_assignments));
+     printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
X    
-  return;
-}
-
-/*--------------------------------------------------------------------*/
-
-static int 
-device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length, 
-	       int *device_type)
-{
-  struct im_scb scb;
-  struct im_tsb tsb;
-  unsigned char buf[256];
-  int retries;
-
-  /* if no valid device found, return immediately with 0 */
-  if (!(device_inquiry(shpnt, ldn, buf))) return 0;
-   
-  /*if device is CD_ROM, assume block size 2048 and return */
-  if (buf[0] == TYPE_ROM)
-    {
-      *device_type = TYPE_ROM;
-      *block_length = 2048; /* (standard blocksize for yellow-/red-book) */
-      return 1;
-    }
-  
-  if (buf[0] == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM 
-			      therefore, the block_length is also 2048. */
-    {
-      *device_type = TYPE_WORM;
-      *block_length = 2048;
-      return 1;
-    }
-   
-  /* if device is disk, use "read capacity" to find its block size */
-  if (buf[0] == TYPE_DISK)
-    {
-      *device_type = TYPE_DISK;
-
-      for (retries = 0; retries < 3; retries++)
-	{
-	  /*fill scb with read capacity command */
-	  scb.command = IM_READ_CAPACITY_CMD;
-	  scb.enable = IM_READ_CONTROL;
-	  scb.sys_buf_adr = virt_to_bus(buf);
-	  scb.sys_buf_length = 8;
-	  scb.tsb_adr = virt_to_bus(&tsb);
-
-	  /*issue scb to passed ldn, and busy wait for interrupt */
-	  got_interrupt = 0;
-	  issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn);
-	  while (!got_interrupt)
-	    barrier ();
-
-	  /*if got capacity, get block length and return one device found */
-	  if (stat_result == IM_SCB_CMD_COMPLETED)
-	    {
-	      *block_length = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
-	      return 1;
-	    }
-	}
-
-      /*if all three retries failed, return "no device at this ldn" */
-      if (retries >= 3)
-	return 0;
-    }
-
-  /* if this is a magneto-optical drive, treat it like a harddisk */
-  if (buf[0] == TYPE_MOD)
-    {
-      *device_type = TYPE_MOD;
-
-      for (retries = 0; retries < 3; retries++)
-	{
-	  /*fill scb with read capacity command */
-	  scb.command = IM_READ_CAPACITY_CMD;
-	  scb.enable = IM_READ_CONTROL;
-	  scb.sys_buf_adr = virt_to_bus(buf);
-	  scb.sys_buf_length = 8;
-	  scb.tsb_adr = virt_to_bus(&tsb);
-
-	  /*issue scb to passed ldn, and busy wait for interrupt */
-	  got_interrupt = 0;
-	  issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn);
-	  while (!got_interrupt)
-	    barrier ();
-
-	  /*if got capacity, get block length and return one device found */
-	  if (stat_result == IM_SCB_CMD_COMPLETED)
-	    {
-	      *block_length = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
-	      return 1;
-	    }
-	}
-
-      /*if all three retries failed, return "no device at this ldn" */
-      if (retries >= 3)
-	return 0;
-    }   
+   /* reset the counters for statistics on the current adapter */
+   IBM_DS(host_index).total_accesses = 0;
+   IBM_DS(host_index).total_interrupts = 0;
+   IBM_DS(host_index).dynamical_assignments = 0;
+   memset (IBM_DS(host_index).ldn_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_access));
+   memset (IBM_DS(host_index).ldn_read_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_read_access));
+   memset (IBM_DS(host_index).ldn_write_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_write_access));
+   memset (IBM_DS(host_index).ldn_inquiry_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_inquiry_access));
+   memset (IBM_DS(host_index).ldn_modeselect_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_modeselect_access));
+   memset (IBM_DS(host_index).ldn_assignments, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_assignments));
X    
-  if (buf[0] == TYPE_TAPE) /* TAPE-device found */
-    {
-      *device_type = TYPE_TAPE;
-      *block_length = 0; /* not in use (setting by mt and mtst in op.) */
-      return 1;   
-    }
-
-  if (buf[0] == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/
-    {
-      *device_type = TYPE_PROCESSOR;
-      *block_length = 0; /* they set their stuff on drivers */
-      return 1;
-    }
-  
-  if (buf[0] == TYPE_SCANNER) /* other SCSI-scanners */
-    {
-      *device_type = TYPE_SCANNER;
-      *block_length = 0; /* they set their stuff on drivers */
-      return 1;
-    }
-
-  if (buf[0] == TYPE_MEDIUM_CHANGER) /* Medium-Changer */
-    {
-      *device_type = TYPE_MEDIUM_CHANGER;
-      *block_length = 0; /* One never knows, what to expect on a medium
-			    changer device. */
-      return 1;
-    }
-
-  /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are
-     ignored! MO-drives are now supported and treated as harddisk. */   
-  return 0;
+   return;
X }
X 
X /*--------------------------------------------------------------------*/
X 
-#ifdef CONFIG_SCSI_IBMMCA
-
-void 
-ibmmca_scsi_setup (char *str, int *ints)
+static int device_exists (int host_index, int ldn, int *block_length, 
+			  int *device_type)
X {
-   if( str && !strcmp( str, "display" ) ) {
-   	use_display = 1;
-   } else if( ints ) {
-	   int i;
-	   for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) {
-	      io_port[i] = ints[2*i+2];
-	      scsi_id[i] = ints[2*i+2];
-	   }
-   }
-}
+   unsigned char *buf;
+   
+   /* if no valid device found, return immediately with 0 */
+   if (!(device_inquiry(host_index, ldn)))
+     return 0;
+   
+   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
X 
-#endif
+   /*if device is CD_ROM, assume block size 2048 and return */
+   if (*buf == TYPE_ROM)
+     {
+	*device_type = TYPE_ROM;
+	*block_length = 2048; /* (standard blocksize for yellow-/red-book) */
+	return 1;
+     }
+   
+   if (*buf == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM 
+			     therefore, the block_length is also 2048. */
+     {
+	*device_type = TYPE_WORM;
+	*block_length = 2048;
+	return 1;
+     }
+   
+   /* if device is disk, use "read capacity" to find its block size */
+   if (*buf == TYPE_DISK)
+     {
+	*device_type = TYPE_DISK;
+        if (read_capacity( host_index, ldn))
+	  {
+	     *block_length = *(buf+7) + (*(buf+6) << 8) + 
+	                    (*(buf+5) << 16) + (*(buf+4) << 24);
+	     return 1;
+	  }
+	else
+	  return 0;
+     }
+   
+   /* if this is a magneto-optical drive, treat it like a harddisk */
+   if (*buf == TYPE_MOD)
+     {
+	*device_type = TYPE_MOD;
+        if (read_capacity( host_index, ldn))
+	  {
+	     *block_length = *(buf+7) + (*(buf+6) << 8) + 
+	                    (*(buf+5) << 16) + (*(buf+4) << 24);
+	     return 1;
+	  }
+	else
+	  return 0;
+     }   
+   
+   if (*buf == TYPE_TAPE) /* TAPE-device found */
+     {
+	*device_type = TYPE_TAPE;
+	*block_length = 0; /* not in use (setting by mt and mtst in op.) */
+	return 1;   
+     }
+   
+   if (*buf == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/
+     {
+	*device_type = TYPE_PROCESSOR;
+	*block_length = 0; /* they set their stuff on drivers */
+	return 1;
+     }
+   
+   if (*buf == TYPE_SCANNER) /* other SCSI-scanners */
+     {
+	*device_type = TYPE_SCANNER;
+	*block_length = 0; /* they set their stuff on drivers */
+	return 1;
+     }
+   
+   if (*buf == TYPE_MEDIUM_CHANGER) /* Medium-Changer */
+     {
+	*device_type = TYPE_MEDIUM_CHANGER;
+	*block_length = 0; /* One never knows, what to expect on a medium
+			    changer device. */
+	return 1;
+     }
+   
+   /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are
+      ignored! MO-drives are now supported and treated as harddisk. */   
+   return 0;
+}
X 
X /*--------------------------------------------------------------------*/
+   
+#ifdef CONFIG_SCSI_IBMMCA
X 
-int
-ibmmca_detect (Scsi_Host_Template * template)
+void ibmmca_scsi_setup (char *str, int *ints)
X {
-  struct Scsi_Host *shpnt;
-  int port, id, i, list_size, slot;
-  unsigned pos2, pos3;
-
-  /* if this is not MCA machine, return "nothing found" */
-  if (!MCA_bus)
-    return 0;
-
-  /* get interrupt request level */
-  if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
-    {
-      printk("IBM MCA SCSI: Unable to get IRQ %d.\n", IM_IRQ);
-      return 0;
-    }
-
-  /* if ibmmcascsi setup option was passed to kernel, return "found" */
-  for (i = 0; i < IM_MAX_HOSTS; i++)
-    if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8)
-      {
-      printk("IBM MCA SCSI: forced detection, io=0x%x, scsi id=%d.\n",
-              io_port[i], scsi_id[i]);
-      ibmmca_register(template, io_port[i], scsi_id[i]);
-      }
-  if (found) return found;
+   int i, j, io_base, id_base;
+   char *token;
+   
+   io_base = 0;
+   id_base = 0;
+   
+   if (str)
+     {
+	token = strtok(str,",");
+	j = 0;
+	while (token)
+	  {
+	     if (!strcmp(token,"display"))
+	       {
+		  use_display = 1;
+	       }
+	     if (!strcmp(token,"adisplay"))
+	       {
+		  use_adisplay = 1;
+	       }
+	     if (!strcmp(token,"bypass"))
+	       {
+		  bypass_controller = 1;
+	       }
+	     if (!strcmp(token,"normal"))
+	       {
+		  ibm_ansi_order = 0;
+	       }
+	     if (!strcmp(token,"ansi"))
+	       {
+		  ibm_ansi_order = 1;
+	       }
+	     if ( (*token == '-') || (isdigit(*token)) )
+	       {
+		  if (!(j%2) && (io_base < IM_MAX_HOSTS))
+		    {
+		       io_port[io_base++] = simple_strtoul(token,NULL,0);
+		    }
+		  if ((j%2) && (id_base < IM_MAX_HOSTS))
+		    {
+		       scsi_id[id_base++] = simple_strtoul(token,NULL,0);
+		    }
+		  j++;
+	       }
+	     token = strtok(NULL,",");
+	  }
+     }
+   else if (ints)
+     {
+	for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) 
+	  {
+	     io_port[i] = ints[2*i+2];
+	     scsi_id[i] = ints[2*i+2];
+	  }
+     }
+   return;
+}
X 
-    /*
-     * Patched by ZP Gu to work with the 9556 as well; the 9556 has
-     * pos2 = 05, but it should be 00, as it should be interfaced
-     * via port = 0x3540.
-     */
-
-  /* first look for the SCSI integrated on the motherboard */
-  pos2 = mca_read_stored_pos(MCA_INTEGSCSI, 2);
-//  if (pos2 != 0xff) {
-    if ((pos2 & 1) == 0) {
-      port = IM_IO_PORT + ((pos2 & 0x0e) << 2);
-    } else {
-      port = IM_IO_PORT;
-    }
-      pos3 = mca_read_stored_pos(MCA_INTEGSCSI, 3);
-      id = (pos3 & 0xe0) >> 5;
-
-      printk("IBM MCA SCSI: integrated SCSI found, io=0x%x, scsi id=%d.\n",
-              port, id);
-      if ((shpnt = ibmmca_register(template, port, id)))
-        {
-          mca_set_adapter_name(MCA_INTEGSCSI, "PS/2 Integrated SCSI");
-          mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
-                                 shpnt);
-        }
-//    }
-
-  /* now look for other adapters */
-  list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
-  for (i = 0; i < list_size; i++)
-    {
-      slot = 0;
-      while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
-             != MCA_NOTFOUND)
-        {
-          pos2 = mca_read_stored_pos(slot, 2);
-          pos3 = mca_read_stored_pos(slot, 3);
-          port = IM_IO_PORT + ((pos2 & 0x0e) << 2);
-          id = (pos3 & 0xe0) >> 5;
-          printk ("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d.\n",
-                  subsys_list[i].description, slot + 1, port, id);
-          if ((shpnt = ibmmca_register(template, port, id)))
-            {
-              mca_set_adapter_name (slot, subsys_list[i].description);
-              mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
-                                      shpnt);
-            }
-          slot++;
-        }
-    }
-
-  if (!found) {
-    free_irq (IM_IRQ, hosts);
-    printk("IBM MCA SCSI: No adapter attached.\n");
-  }
+#endif
+
+/*--------------------------------------------------------------------*/
+
+static int ibmmca_getinfo (char *buf, int slot, void *dev)
+{
+   struct Scsi_Host *shpnt;
+   int len, special;
+   unsigned int pos2, pos3;
+   static unsigned long flags;
+     
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();   
+#else
+   spin_lock_irqsave(&info_lock, flags);
+#endif   
+   
+   shpnt = dev; /* assign host-structure to local pointer */
+   len = 0; /* set filled text-buffer index to 0 */
+   /* get the _special contents of the hostdata structure */
+   special = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
+   pos2 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2;
+   pos3 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3;
+   
+   if (special == FORCED_DETECTION) /* forced detection */
+     {
+	len += sprintf (buf + len, "Adapter cathegory: forced detected\n");
+	len += sprintf(buf + len, "***************************************\n");
+	len += sprintf(buf + len, "***  Forced detected SCSI Adapter   ***\n");
+	len += sprintf(buf + len, "***  No chip-information available  ***\n");
+	len += sprintf(buf + len, "***************************************\n");
+     }
+   else if (special == INTEGRATED_SCSI)
+     { /* if the integrated subsystem has been found automatically: */
+	len += sprintf (buf + len, "Adapter cathegory: integrated\n");
+	len += sprintf (buf + len, "Chip revision level: %d\n",
+			((pos2 & 0xf0) >> 4));
+	len += sprintf (buf + len, "Chip status: %s\n",
+			(pos2 & 1) ? "enabled" : "disabled");
+	len += sprintf (buf + len, "8 kByte NVRAM status: %s\n",
+			(pos2 & 2) ? "locked" : "accessible");
+     }
+   else if ((special>=0)&&
+	   (special<(sizeof(subsys_list)/sizeof(struct subsys_list_struct))))
+     { /* if the subsystem is a slot adapter */
+	len += sprintf (buf + len, "Adapter cathegory: slot-card\n");
+	len += sprintf (buf + len, "Chip revision level: %d\n",
+			((pos2 & 0xf0) >> 4));
+	len += sprintf (buf + len, "Chip status: %s\n",
+			(pos2 & 1) ? "enabled" : "disabled");
+	len += sprintf (buf + len, "Port offset: 0x%x\n",
+			((pos2 & 0x0e) << 2));
+     }
+   else
+     {
+	len += sprintf (buf + len, "Adapter cathegory: unknown\n");
+     }
+   /* common subsystem information to write to the slotn file */
+   len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
+   len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x",
+		   (unsigned int)(shpnt->io_port), 
+		   (unsigned int)(shpnt->io_port+7));
+   /* Now make sure, the bufferlength is devideable by 4 to avoid
+    * paging problems of the buffer. */
+   while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) )
+     {
+	len += sprintf (buf + len, " ");
+     }
+   len += sprintf (buf + len, "\n");
X 
-  return found;
+#ifdef OLDKERN   
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&info_lock, flags);
+#endif   
+   return len;
+}
+   
+int ibmmca_detect (Scsi_Host_Template * scsi_template)
+{
+   struct Scsi_Host *shpnt;
+   int port, id, i, j, list_size, slot;
+   
+   found = 0; /* make absolutely sure, that found is set to 0 */
+   
+   /* if this is not MCA machine, return "nothing found" */
+   if (!MCA_bus)
+     {
+	printk("IBM MCA SCSI: No Microchannel-bus support present -> Aborting.\n");
+	return 0;
+     }
+   else
+     printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
+   
+   /* get interrupt request level */
+#ifdef OLDKERN
+   if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi",
+		    hosts))
+#else
+   if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmcascsi",
+		    hosts))
+#endif
+     {
+	printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
+	return 0;
+     }
+   
+   /* if ibmmcascsi setup option was passed to kernel, return "found" */
+   for (i = 0; i < IM_MAX_HOSTS; i++)
+     if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8)
+     {
+	printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n",
+	       io_port[i], scsi_id[i]);
+	if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i],
+		     "forced detected SCSI Adapter")))
+	  {
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = 
+	       FORCED_DETECTION;
+	     mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
+	     mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
+				    shpnt);
+	     mca_mark_as_used(MCA_INTEGSCSI);
+	  }	
+     }
+   if (found) return found;
+   
+   /* The POS2-register of all PS/2 model SCSI-subsystems has the following
+    * interpretation of bits:
+    *                             Bit 7 - 4 : Chip Revision ID (Release)
+    *                             Bit 3 - 2 : Reserved
+    *                             Bit 1     : 8k NVRAM Disabled
+    *                             Bit 0     : Chip Enable (EN-Signal)
+    * The POS3-register is interpreted as follows:
+    *                             Bit 7 - 5 : SCSI ID
+    *                             Bit 4     : Reserved = 0
+    *                             Bit 3 - 0 : Reserved = 0
+    * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
+    * Interfaces (1991)"). 
+    * In short words, this means, that IBM PS/2 machines only support 
+    * 1 single subsystem by default. The slot-adapters must have another 
+    * configuration on pos2. Here, one has to assume the following
+    * things for POS2-register:
+    *                             Bit 7 - 4 : Chip Revision ID (Release)
+    *                             Bit 3 - 1 : port offset factor
+    *                             Bit 0     : Chip Enable (EN-Signal)
+    * As I found a patch here, setting the IO-registers to 0x3540 forced,
+    * as there was a 0x05 in POS2 on a model 56, I assume, that the 
+    * port 0x3540 must be fix for integrated SCSI-controllers.
+    * Ok, this discovery leads to the following implementation: (M.Lang) */
+
+   /* first look for the IBM SCSI integrated subsystem on the motherboard */
+   for (j=0;j<8;j++) /* read the pos-information */
+     pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j);
+   /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present  */
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 19'
echo 'File patch-2.2.8 is continued in part 20'
echo 20 > _shar_seq_.tmp
#!/bin/sh
# this is part 20 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 20; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+   if (( pos[2] != 0xff) || (pos[3] != 0xff ))
+     {
+	if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
+	  {
+	     port = IM_IO_PORT;
+	  } 
+	else 
+	  { /* if disabled, no IRQs will be generated, as the chip won't
+	     * listen to the incomming commands and will do really nothing,
+	     * except for listening to the pos-register settings. If this
+	     * happens, I need to hugely think about it, as one has to
+	     * write something to the MCA-Bus pos register in order to
+	     * enable the chip. Normally, IBM-SCSI won't pass the POST,
+	     * when the chip is disabled (see IBM tech. ref.). */
+	     port = IM_IO_PORT; /* anyway, set the portnumber and warn */
+	     printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+	     printk("              SCSI-operations may not work.\n");
+	  }      
+	id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
+	
+	/* give detailed information on the subsystem. This helps me 
+	 * additionally during debugging and analyzing bug-reports. */
+	printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n",
+	       port, id);
+	printk("              chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n",
+	       ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible",
+	       (pos[2] & 1) ? "enabled." : "disabled.");
+
+	/* register the found integrated SCSI-subsystem */
+	if ((shpnt = ibmmca_register(scsi_template, port, id,
+		     "IBM Integrated SCSI Controller")))
+	  {
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = 
+	       INTEGRATED_SCSI;
+	     mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
+	     mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
+				    shpnt);
+	     mca_mark_as_used(MCA_INTEGSCSI);
+	  }
+     }
+   
+   /* now look for other adapters in MCA slots, */   
+   /* determine the number of known IBM-SCSI-subsystem types */
+   /* see the pos[2] dependence to get the adapter port-offset. */
+   list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+   for (i = 0; i < list_size; i++)
+     { /* scan each slot for a fitting adapter id */
+	slot = 0; /* start at slot 0 */
+	while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
+	       != MCA_NOTFOUND)
+	  { /* scan through all slots */
+	     for (j=0;j<8;j++) /* read the pos-information */
+	       pos[j] = mca_read_stored_pos(slot, j);
+	     if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
+	       { /* (explanations see above) */
+		  port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+	       } 
+	     else 
+	       { /* anyway, set the portnumber and warn */
+		  port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); 
+		  printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+		  printk("              SCSI-operations may not work.\n");
+	       }      	     
+	     id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+	     printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
+		     subsys_list[i].description, slot + 1, port, id);
+	     printk("              chip rev.=%d, port-offset=0x%x, subsystem=%s\n",
+		    ((pos[2] & 0xf0) >> 4), 
+		    ((pos[2] & 0x0e) << 2),
+		    (pos[2] & 1) ? "enabled." : "disabled.");
+	     
+	     /* register the hostadapter */
+	     if ((shpnt = ibmmca_register(scsi_template, port, id,
+		          subsys_list[i].description)))
+	       {
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
+
+		  mca_set_adapter_name (slot, subsys_list[i].description);
+		  mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
+					  shpnt);
+		  mca_mark_as_used(slot);
+	       }
+	     slot++; /* advance to next slot */
+	  } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
+     }
+   
+   if (!found) 
+     { /* maybe ESDI, or other producers' SCSI-hosts */
+	free_irq (IM_IRQ, hosts);
+	printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
+     }  
+   return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
X }
X 
X static struct Scsi_Host *
-ibmmca_register(Scsi_Host_Template * template, int port, int id)
+ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id,
+		char *hostname)
X {
-  struct Scsi_Host *shpnt;
-  int i, j;
+   struct Scsi_Host *shpnt;
+   int i, j;
+   unsigned int ctrl;
+   
+   /* check I/O region */
+   if (check_region(port, IM_N_IO_PORT))
+     {
+	printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n",
+	       port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
+	return NULL;
+     }
+   
+   /* register host */
+   shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
+   if (!shpnt)
+     {
+	printk("IBM MCA SCSI: Unable to register host.\n");
+	return NULL;
+     }
+   
+   /* request I/O region */
+   request_region(port, IM_N_IO_PORT, hostname);
X 
-  /* check I/O region */
-  if (check_region(port, IM_N_IO_PORT))
-    {
-      printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x.\n",
-        port, port + IM_N_IO_PORT);
-      return NULL;
-    }
-
-  /* register host */
-  shpnt = scsi_register(template, sizeof(struct ibmmca_hostdata));
-  if (!shpnt)
-    {
-      printk("IBM MCA SCSI: Unable to register host.\n");
-      return NULL;
-    }
-
-  /* request I/O region */
-  request_region(port, IM_N_IO_PORT, "ibmmca");
-
-  hosts[found++] = shpnt;
-  shpnt->irq = IM_IRQ;
-  shpnt->io_port = port;
-  shpnt->n_io_port = IM_N_IO_PORT;
-  shpnt->this_id = id;
-
-  reset_status = IM_RESET_NOT_IN_PROGRESS;
-
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++)
-      get_ldn[i][j] = MAX_LOG_DEV;
-
-  /* check which logical devices exist */
-  local_checking_phase_flag = 1;
-  check_devices(shpnt);
-  local_checking_phase_flag = 0;
+   hosts[found] = shpnt; /* add new found hostadapter to the list */
+   shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
+   shpnt->io_port = port;
+   shpnt->n_io_port = IM_N_IO_PORT;
+   shpnt->this_id = id;
+   /* now, the SCSI-subsystem is connected to Linux */
X 
-  /* an ibm mca subsystem has been detected */
-  return shpnt;
+   ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */
+#ifdef IM_DEBUG_PROBE
+   printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n",
+	  ctrl,inb(IM_STAT_REG(found)));
+   printk("IBM MCA SCSI: This adapters' POS-registers: ");
+   for (i=0;i<8;i++)
+     printk("%x ",pos[i]);
+   printk("\n");
+   if (bypass_controller)
+     printk("IBM MCA SCSI: Subsystem SCSI-commands get bypassed.\n");
+#endif
+   
+   reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
+
+   for (i = 0; i < 8; i++) /* reset the tables */
+     for (j = 0; j < 8; j++)
+     get_ldn(found)[i][j] = MAX_LOG_DEV;
+
+   /* check which logical devices exist */
+   local_checking_phase_flag(found) = 1;
+   check_devices(found); /* call by value, using the global variable hosts*/
+   local_checking_phase_flag(found) = 0;
+   
+   found++; /* now increase index to be prepared for next found subsystem */
+   /* an ibm mca subsystem has been detected */
+   return shpnt;
X }
X 
X /*--------------------------------------------------------------------*/
X 
-int 
-ibmmca_command (Scsi_Cmnd * cmd)
+int ibmmca_command (Scsi_Cmnd * cmd)
X {
X   ibmmca_queuecommand (cmd, internal_done);
X   cmd->SCp.Status = 0;
@@ -1678,8 +1765,7 @@
X 
X /*--------------------------------------------------------------------*/
X 
-int
-ibmmca_release(struct Scsi_Host *shpnt)
+int ibmmca_release(struct Scsi_Host *shpnt)
X {
X   release_region(shpnt->io_port, shpnt->n_io_port);
X   if (!(--found))
@@ -1708,231 +1794,267 @@
X    are sufficient. (The adapter uses always ldn=15, at whatever pun it is.) */
X int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
X {
-  unsigned int ldn;
-  unsigned int scsi_cmd;
-  struct im_scb *scb;
-  struct Scsi_Host *shpnt = cmd->host;
-  
-  int current_ldn;
-  int id,lun;
-
-  /* use industry standard ordering of the IDs */
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-  int target = 6 - cmd->target;
-#else
-  int target = cmd->target;
-#endif
-
-  /*if (target,lun) is NO LUN or not existing at all, return error */
-  if ((get_scsi[target][cmd->lun] == TYPE_NO_LUN)||
-      (get_scsi[target][cmd->lun] == TYPE_NO_DEVICE))
+   unsigned int ldn;
+   unsigned int scsi_cmd;
+   struct im_scb *scb;
+   struct Scsi_Host *shpnt;
+   int current_ldn;
+   int id,lun;
+   int target;
+   int host_index;
+   
+   if (ibm_ansi_order)
+     target = 6 - cmd->target;
+   else
+     target = cmd->target;
+   
+   shpnt = cmd->host;
+   
+   /* search for the right hostadapter */
+   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+   
+   if (!hosts[host_index])
+     { /* invalid hostadapter descriptor address */
+	cmd->result = DID_NO_CONNECT << 16;
+	done (cmd);
+	return 0;
+     }
+   
+   /*if (target,lun) is NO LUN or not existing at all, return error */
+   if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)||
+       (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE))
X      {
X 	cmd->result = DID_NO_CONNECT << 16;
X 	done (cmd);
X 	return 0;
X      }
X    
-  /*if (target,lun) unassigned, do further checks... */
-  ldn = get_ldn[target][cmd->lun];
-  if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */
-    {
-      if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */
-	 {
-	    current_ldn = next_ldn; /* stop-value for one circle */
-	    while (ld[next_ldn].cmd) /* search for a occupied, but not in */
-	      {                      /* command-processing ldn. */
-		 next_ldn ++;
-		 if (next_ldn>=MAX_LOG_DEV) 
-		   next_ldn = 7;
-		 if (current_ldn == next_ldn) /* One circle done ? */
-		   {         /* no non-processing ldn found */
-		      printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n");
-		      printk("              On ldn 7-14 SCSI-commands everywhere in progress.\n");
-		      printk("              Reporting DID_NO_CONNECT for device (%d,%d).\n",
-			     target, cmd->lun);
-		      cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
-		      done (cmd);
-		      return 0;
-		   }
-	      }
-
- /* unmap non-processing ldn */
-	    for (id=0; id<8; id ++)
-	      for (lun=0; lun<8; lun++)
-	      {
-		 if (get_ldn[id][lun] == next_ldn)
-		   {
-		      get_ldn[id][lun] = TYPE_NO_DEVICE; /* unmap entry */
-		      goto DYN_ASSIGN;  /* jump out as fast as possible */
-		   }
-	      }
-
-DYN_ASSIGN:	    
-	    /* unassign found ldn (pun,lun does not matter for remove) */
-	    immediate_assign(shpnt,0,0,next_ldn,REMOVE_LDN);
-	    /* assign found ldn to aimed pun,lun */
-	    immediate_assign(shpnt,target,cmd->lun,next_ldn,SET_LDN);
-	    /* map found ldn to pun,lun */
-	    get_ldn[target][cmd->lun] = next_ldn;
-            /* change ldn to the right value, that is now next_ldn */
-	    ldn = next_ldn;
-	    /* set reduced interrupt_handler-mode for checking */
-	    local_checking_phase_flag = 1;
-	    /* get device information for ld[ldn] */
-	    if (device_exists (shpnt, ldn, &ld[ldn].block_length,
-			       &ld[ldn].device_type))
+   /*if (target,lun) unassigned, do further checks... */
+   ldn = get_ldn(host_index)[target][cmd->lun];
+   if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */
+     {
+	if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */
+	  {
+	     current_ldn = next_ldn(host_index); /* stop-value for one circle */
+	     while (ld(host_index)[next_ldn(host_index)].cmd) /* search for a occupied, but not in */
+	       {                      /* command-processing ldn. */
+		  next_ldn(host_index)++;
+		  if (next_ldn(host_index)>=MAX_LOG_DEV) 
+		    next_ldn(host_index) = 7;
+		  if (current_ldn == next_ldn(host_index)) /* One circle done ? */
+		    {         /* no non-processing ldn found */
+		       printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n");
+		       printk("              On ldn 7-14 SCSI-commands everywhere in progress.\n");
+		       printk("              Reporting DID_NO_CONNECT for device (%d,%d).\n",
+			      target, cmd->lun);
+		       cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
+		       done (cmd);
+		       return 0;
+		    }
+	       }
+	     
+ /* unmap non-processing ldn */
+	     for (id=0; id<8; id ++)
+	       for (lun=0; lun<8; lun++)
X 	       {
-		 ld[ldn].cmd = 0; /* To prevent panic set 0, because
-				     devices that were not assigned,
-				     should have nothing in progress. */
+		  if (get_ldn(host_index)[id][lun] == next_ldn(host_index))
+		    {
+		       get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE; 
+		       /* unmap entry */
+		    }
+	       }
+	     /* set reduced interrupt_handler-mode for checking */
+	     local_checking_phase_flag(host_index) = 1;
+	     /* unassign found ldn (pun,lun does not matter for remove) */
+	     immediate_assign(host_index,0,0,next_ldn(host_index),REMOVE_LDN);
+	     /* assign found ldn to aimed pun,lun */
+	     immediate_assign(host_index,target,cmd->lun,next_ldn(host_index),SET_LDN);
+	     /* map found ldn to pun,lun */
+	     get_ldn(host_index)[target][cmd->lun] = next_ldn(host_index);
+	     /* change ldn to the right value, that is now next_ldn */
+	     ldn = next_ldn(host_index);
+	     /* get device information for ld[ldn] */
+	     if (device_exists (host_index, ldn, 
+				&ld(host_index)[ldn].block_length,
+				&ld(host_index)[ldn].device_type))
+	       {
+		  ld(host_index)[ldn].cmd = 0; /* To prevent panic set 0, because
+						devices that were not assigned,
+						should have nothing in progress. */
X 		  
-		 /* increase assignment counters for statistics in /proc */
-		 IBM_DS.dynamical_assignments++;
-		 IBM_DS.ldn_assignments[ldn]++;
+		  /* increase assignment counters for statistics in /proc */
+		  IBM_DS(host_index).dynamical_assignments++;
+		  IBM_DS(host_index).ldn_assignments[ldn]++;
X 	       }
-	    else
-	         /* panic here, because a device, found at boottime has 
-		    vanished */
-	         panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
-		       ldn, target, cmd->lun);
-	    
-	    /* set back to normal interrupt_handling */
-	    local_checking_phase_flag = 0;
-	    
-	    /* Information on syslog terminal */
-	    printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
-		   ldn, target, cmd->lun);
-	    
-	    /* increase next_ldn for next dynamical assignment */ 
-	    next_ldn ++;
-	    if (next_ldn>=MAX_LOG_DEV) next_ldn = 7;
-	 }       
-      else
-	 {  /* wall against Linux accesses to the subsystem adapter */	 
-            cmd->result = DID_NO_CONNECT << 16;
-            done (cmd);
-            return 0;
-	 }
-    }
-
-  /*verify there is no command already in progress for this log dev */
-  if (ld[ldn].cmd)
-    panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n");
-
-  /*save done in cmd, and save cmd for the interrupt handler */
-  cmd->scsi_done = done;
-  ld[ldn].cmd = cmd;
-
-  /*fill scb information independent of the scsi command */
-  scb = &(ld[ldn].scb);
-  scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
-  scb->tsb_adr = virt_to_bus(&(ld[ldn].tsb));
-  if (cmd->use_sg)
-    {
-      int i = cmd->use_sg;
-      struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer;
-      if (i > 16)
-	panic ("IBM MCA SCSI: scatter-gather list too long.\n");
-      while (--i >= 0)
-	{
-	  ld[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
-	  ld[ldn].sge[i].byte_length = sl[i].length;
-	}
-      scb->enable |= IM_POINTER_TO_LIST;
-      scb->sys_buf_adr = virt_to_bus(&(ld[ldn].sge[0]));
-      scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge);
-    }
-  else
-    {
-      scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
-      scb->sys_buf_length = cmd->request_bufflen;
-    }
-
-  /*fill scb information dependent on scsi command */
-  scsi_cmd = cmd->cmnd[0];
+	     else
+	       /* panic here, because a device, found at boottime has 
+		vanished */
+	       panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
+		     ldn, target, cmd->lun);
+	     
+	     /* set back to normal interrupt_handling */
+	     local_checking_phase_flag(host_index) = 0;
+	     
+	     /* Information on syslog terminal */
+	     printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
+		    ldn, target, cmd->lun);
+	     
+	     /* increase next_ldn for next dynamical assignment */ 
+	     next_ldn(host_index)++;
+	     if (next_ldn(host_index)>=MAX_LOG_DEV) 
+	       next_ldn(host_index) = 7;
+	  }       
+	else
+	  {  /* wall against Linux accesses to the subsystem adapter */	 
+	     cmd->result = DID_BAD_TARGET << 16;
+	     done (cmd);
+	     return 0;
+	  }
+     }
+   
+   /*verify there is no command already in progress for this log dev */
+   if (ld(host_index)[ldn].cmd)
+     panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n");
+   
+   /*save done in cmd, and save cmd for the interrupt handler */
+   cmd->scsi_done = done;
+   ld(host_index)[ldn].cmd = cmd;
+   
+   /*fill scb information independent of the scsi command */
+   scb = &(ld(host_index)[ldn].scb);
+   ld(host_index)[ldn].tsb.dev_status = 0;
+   scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
+   scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb));
+   if (cmd->use_sg)
+     {
+	int i = cmd->use_sg;
+	struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer;
+	if (i > 16)
+	  panic ("IBM MCA SCSI: scatter-gather list too long.\n");
+	while (--i >= 0)
+	  {
+	     ld(host_index)[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
+	     ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
+	  }
+	scb->enable |= IM_POINTER_TO_LIST;
+	scb->sys_buf_adr = virt_to_bus(&(ld(host_index)[ldn].sge[0]));
+	scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge);
+     }
+   else
+     {
+	scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
+	scb->sys_buf_length = cmd->request_bufflen;
+     }
+   
+   /*fill scb information dependent on scsi command */
+   scsi_cmd = cmd->cmnd[0];
X    
X #ifdef IM_DEBUG_CMD
-  printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
+   printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
X #endif
-
-  /* for specific device-type debugging: */
+   
+   /* for specific device-type debugging: */
X #ifdef IM_DEBUG_CMD_SPEC_DEV
-  if (ld[ldn].device_type==IM_DEBUG_CMD_DEVICE)
+   if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE)
X      printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", 
-	    ld[ldn].device_type, scsi_cmd, ldn);
+	    ld(host_index)[ldn].device_type, scsi_cmd, ldn);
X #endif
-
-  /* for possible panics store current command */
-  last_scsi_command = scsi_cmd; 
X    
-  /* update statistical info */
-  IBM_DS.total_accesses++;
-  IBM_DS.ldn_access[ldn]++;
-   
-  switch (scsi_cmd)
-    {
-    case READ_6:
-    case WRITE_6:
-    case READ_10:
-    case WRITE_10:
-    case READ_12:
-    case WRITE_12:       
-      /* statistics for proc_info */
-      if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12))
-	 IBM_DS.ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
-      else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)||
-	       (scsi_cmd == WRITE_12))
-	 IBM_DS.ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
-
-      /* Distinguish between disk and other devices. Only disks (that are the
-	 most frequently accessed devices) should be supported by the 
+   /* for possible panics store current command */
+   last_scsi_command(host_index)[ldn] = scsi_cmd; 
+   last_scsi_type(host_index)[ldn] = IM_SCB;
+   
+   /* update statistical info */
+   IBM_DS(host_index).total_accesses++;
+   IBM_DS(host_index).ldn_access[ldn]++;
+   
+   switch (scsi_cmd)
+     {
+      case READ_6:
+      case WRITE_6:
+      case READ_10:
+      case WRITE_10:
+      case READ_12:
+      case WRITE_12:       
+	/* statistics for proc_info */
+	if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12))
+	  IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
+	else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)||
+		 (scsi_cmd == WRITE_12))
+	  IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
+	
+	/* Distinguish between disk and other devices. Only disks (that are the
+	   most frequently accessed devices) should be supported by the 
X          IBM-SCSI-Subsystem commands. */
-      switch (ld[ldn].device_type)
-	 {
-	  case TYPE_DISK: /* for harddisks enter here ... */
-	  case TYPE_MOD:  /* ... try it also for MO-drives (send flames as */
-			  /* you like, if this won't work.) */
-           if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
-	       scsi_cmd == READ_12)
-	     {
-	       scb->command = IM_READ_DATA_CMD;
-	       scb->enable |= IM_READ_CONTROL;
-	     }
-           else
-	     {
-	       scb->command = IM_WRITE_DATA_CMD;
-	     }
-           if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6)
-	     {
-	       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) |
-	         (((unsigned) cmd->cmnd[2]) << 8) |
-	         ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
-	       scb->u2.blk.count = (unsigned) cmd->cmnd[4];
-	     }
-           else
-	     {
-	       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) |
-	         (((unsigned) cmd->cmnd[4]) << 8) |
-	         (((unsigned) cmd->cmnd[3]) << 16) |
-	         (((unsigned) cmd->cmnd[2]) << 24);
-	       scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
-	         (((unsigned) cmd->cmnd[7]) << 8);
-	     }
-           scb->u2.blk.length = ld[ldn].block_length;
-	   if (++disk_rw_in_progress == 1)
-	      PS2_DISK_LED_ON (shpnt->host_no, target);
-	  break;
-	    
-	  /* for other devices, enter here. Other types are not known by
-	     Linux! TYPE_NO_LUN is forbidden as valid device. */
-          case TYPE_ROM:
-	  case TYPE_TAPE:
-	  case TYPE_PROCESSOR:
-	  case TYPE_WORM:
-	  case TYPE_SCANNER:
-	  case TYPE_MEDIUM_CHANGER:
-	  
-	   /* If there is a sequential-device, IBM recommends to use
+	switch (ld(host_index)[ldn].device_type)
+	  {
+	   case TYPE_DISK: /* for harddisks enter here ... */
+	   case TYPE_MOD:  /* ... try it also for MO-drives (send flames as */
+	                   /*     you like, if this won't work.) */
+	     if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
+		 scsi_cmd == READ_12)
+	       { /* read command preparations */
+		  if (bypass_controller)
+		    {
+		       scb->command = IM_OTHER_SCSI_CMD_CMD;
+		       scb->enable |= IM_READ_CONTROL;
+		       scb->u1.scsi_cmd_length = cmd->cmd_len;
+		       memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+		    }
+		  else
+		    {
+		       scb->command = IM_READ_DATA_CMD;
+		       scb->enable |= IM_READ_CONTROL;
+		    }
+	       }
+	     else
+	       { /* write command preparations */
+		  if (bypass_controller)
+		    {
+		       scb->command = IM_OTHER_SCSI_CMD_CMD;
+		       scb->u1.scsi_cmd_length = cmd->cmd_len;
+		       memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+		    }
+		  else
+		    { 
+		       scb->command = IM_WRITE_DATA_CMD;
+		    }
+	       }
+	     
+	     if (!bypass_controller)
+	       {		 
+		  if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6)
+		    {
+		       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) |
+			 (((unsigned) cmd->cmnd[2]) << 8) |
+			 ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
+		       scb->u2.blk.count = (unsigned) cmd->cmnd[4];
+		    }
+		  else
+		    {
+		       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) |
+			 (((unsigned) cmd->cmnd[4]) << 8) |
+			 (((unsigned) cmd->cmnd[3]) << 16) |
+			 (((unsigned) cmd->cmnd[2]) << 24);
+		       scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
+			 (((unsigned) cmd->cmnd[7]) << 8);
+		    }
+		  scb->u2.blk.length = ld(host_index)[ldn].block_length;
+	       }	    
+	     if (++disk_rw_in_progress == 1)
+	       PS2_DISK_LED_ON (shpnt->host_no, target);
+	     break;
+	     
+	     /* for other devices, enter here. Other types are not known by
+	      Linux! TYPE_NO_LUN is forbidden as valid device. */
+	   case TYPE_ROM:
+	   case TYPE_TAPE:
+	   case TYPE_PROCESSOR:
+	   case TYPE_WORM:
+	   case TYPE_SCANNER:
+	   case TYPE_MEDIUM_CHANGER:
+	     
+	     /* If there is a sequential-device, IBM recommends to use
X 	      IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. 
X 	      Good/modern CD-ROM-drives are capable of
X 	      reading sequential AND random-access. This leads to the problem,
@@ -1943,241 +2065,422 @@
X 	      to have a stable state. In addition, data-access on CD-ROMs
X 	      works faster like that. Strange, but obvious. */
X 	    
-           scb->command = IM_OTHER_SCSI_CMD_CMD;
-	   if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
-	       scsi_cmd == READ_12) /* enable READ */
-              scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-	   else
-	      scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /* assume WRITE */
-	    
-           scb->u1.scsi_cmd_length = cmd->cmd_len;
-           memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-	    
-	   /* Read/write on this non-disk devices is also displayworthy, 
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
+		 scsi_cmd == READ_12) /* enable READ */
+	       {
+		  scb->enable |= IM_READ_CONTROL;
+	       }
+	     
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	     
+	     /* Read/write on this non-disk devices is also displayworthy, 
X 	      so flash-up the LED/display. */
-	   if (++disk_rw_in_progress == 1)
-	      PS2_DISK_LED_ON (shpnt->host_no, target);
-	 break;
-	 }
-      break;
-    case INQUIRY:
-      IBM_DS.ldn_inquiry_access[ldn]++;
-      scb->command = IM_DEVICE_INQUIRY_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-      break;
-
-    case READ_CAPACITY:
-      scb->command = IM_READ_CAPACITY_CMD;
-      scb->enable |= IM_READ_CONTROL;
-      /* the length of system memory buffer must be exactly 8 bytes */
-      if (scb->sys_buf_length >= 8)
-	scb->sys_buf_length = 8;
-      break;
-
-    /* Commands that need read-only-mode (system <- device): */
-    case REQUEST_SENSE:
-      scb->command = IM_REQUEST_SENSE_CMD;
-      scb->enable |= IM_READ_CONTROL;
-      break;
-       
-    /* Commands that need write-only-mode (system -> device): */
-    case MODE_SELECT:
-    case MODE_SELECT_10:
-      IBM_DS.ldn_modeselect_access[ldn]++;
-      scb->command = IM_OTHER_SCSI_CMD_CMD;      
-      scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
-      scb->u1.scsi_cmd_length = cmd->cmd_len;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-      break;
-            
-    /* For other commands, read-only is useful. Most other commands are 
-       running without an input-data-block. */
-    default:
-      scb->command = IM_OTHER_SCSI_CMD_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-      scb->u1.scsi_cmd_length = cmd->cmd_len;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-      break;
-    }
+	     if (++disk_rw_in_progress == 1)
+	       PS2_DISK_LED_ON (shpnt->host_no, target);
+	     break;
+	  }
+	break;
+      case INQUIRY:
+	IBM_DS(host_index).ldn_inquiry_access[ldn]++;
+	if (bypass_controller)
+	  {
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	  }
+	else
+	  {
+	     scb->command = IM_DEVICE_INQUIRY_CMD;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	  }
+	break;	
X 
-  /*issue scb command, and return */
-  issue_cmd (shpnt, virt_to_bus(scb), IM_SCB | ldn);
-  return 0;
+      case READ_CAPACITY:
+	/* the length of system memory buffer must be exactly 8 bytes */
+	if (scb->sys_buf_length > 8)
+	  scb->sys_buf_length = 8;
+	if (bypass_controller)
+	  {
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);	     
+	  }
+	else
+	  {
+	     scb->command = IM_READ_CAPACITY_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	  }
+	break;
+	
+	/* Commands that need read-only-mode (system <- device): */
+      case REQUEST_SENSE:
+	if (bypass_controller)
+	  {
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	  }
+	else
+	  {
+	     scb->command = IM_REQUEST_SENSE_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	  }
+	break;
+	
+	/* Commands that need write-only-mode (system -> device): */
+      case MODE_SELECT:
+      case MODE_SELECT_10:
+	IBM_DS(host_index).ldn_modeselect_access[ldn]++;
+	scb->command = IM_OTHER_SCSI_CMD_CMD;      
+	scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
+	scb->u1.scsi_cmd_length = cmd->cmd_len;
+	memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	break;
+	
+	/* For other commands, read-only is useful. Most other commands are 
+	 running without an input-data-block. */
+      default:
+	scb->command = IM_OTHER_SCSI_CMD_CMD;
+	scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	scb->u1.scsi_cmd_length = cmd->cmd_len;
+	memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	break;
+     }
+   
+   /*issue scb command, and return */
+   issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+ return 0;
X }
X 
X /*--------------------------------------------------------------------*/
X 
-int 
-ibmmca_abort (Scsi_Cmnd * cmd)
+int ibmmca_abort (Scsi_Cmnd * cmd)
X {
-  /* The code below doesn't work right now, so we tell the upper layer
-     that we can't abort. This eventually causes a reset.
-     */
-  return SCSI_ABORT_SNOOZE ;
-
-#if 0
-  struct Scsi_host *shpnt = cmd->host;
-  unsigned int ldn;
-  void (*saved_done) (Scsi_Cmnd *);
+   /* Abort does not work, as the adapter never generates an interrupt on
+    * whatever situation is simulated, even when really pending commands
+    * are running on the adapters' hardware ! */
+   
+   struct Scsi_Host *shpnt;
+   unsigned int ldn;
+   void (*saved_done) (Scsi_Cmnd *);
+   int target;
+   int host_index;
+   static unsigned long flags;
+   unsigned long imm_command;
X 
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-  int target = 6 - cmd->target;
+   /* return SCSI_ABORT_SNOOZE ; */
+
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();   
X #else
-  int target = cmd->target;
-#endif
+   spin_lock_irqsave(&abort_lock, flags);
+#endif         
+   if (ibm_ansi_order)
+     target = 6 - cmd->target;
+   else
+     target = cmd->target;
+   
+   shpnt = cmd->host;
X 
-  /*get logical device number, and disable system interrupts */
-  printk ("IBM MCA SCSI: sending abort to device id=%d lun=%d.\n",
-	  target, cmd->lun);
-  ldn = get_ldn[target][cmd->lun];
-  cli ();
-
-  /*if cmd for this ldn has already finished, no need to abort */
-  if (!ld[ldn].cmd)
-    {
-      /* sti (); */
-      return SCSI_ABORT_NOT_RUNNING;
-    }
-
-  /* Clear ld.cmd, save done function, install internal done, 
-   * send abort immediate command (this enables sys. interrupts), 
-   * and wait until the interrupt arrives. 
-   */
-  ld[ldn].cmd = 0;
-  saved_done = cmd->scsi_done;
-  cmd->scsi_done = internal_done;
-  cmd->SCp.Status = 0;
-  issue_cmd (shpnt, T_IMM_CMD, IM_IMM_CMD | ldn);
-  while (!cmd->SCp.Status)
-    barrier ();
+   /* search for the right hostadapter */
+   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);   
+   
+   if (!hosts[host_index])
+     { /* invalid hostadapter descriptor address */
+	cmd->result = DID_NO_CONNECT << 16;
+	if (cmd->scsi_done)
+	  (cmd->done) (cmd);
+	return SCSI_ABORT_SNOOZE;
+     }
+ 
+   /*get logical device number, and disable system interrupts */
+   printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n",
+	   target, cmd->lun);
+   ldn = get_ldn(host_index)[target][cmd->lun];
+
+   /*if cmd for this ldn has already finished, no need to abort */
+   if (!ld(host_index)[ldn].cmd)
+     {
+#ifdef OLDKERN   
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&abort_lock, flags);
+#endif   	
+	return SCSI_ABORT_NOT_RUNNING;
+     }
X 
-  /*if abort went well, call saved done, then return success or error */
-  if (cmd->result == 0)
-    {
-      cmd->result |= DID_ABORT << 16;
-      saved_done (cmd);
-      return SCSI_ABORT_SUCCESS;
-    }
-  else
-    return SCSI_ABORT_ERROR;
+   /* Clear ld.cmd, save done function, install internal done, 
+    * send abort immediate command (this enables sys. interrupts), 
+    * and wait until the interrupt arrives. 
+    */
+   saved_done = cmd->scsi_done;
+   cmd->scsi_done = internal_done;
+   cmd->SCp.Status = 0;
+   last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
+   last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+   imm_command = inl(IM_CMD_REG(host_index));
+   imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */
+   imm_command |= (unsigned long)(IM_ABORT_IMM_CMD);
+   /* must wait for attention reg not busy */
+   while (1)
+     {
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	  break;
+#ifdef OLDKERN	
+	restore_flags (flags);
+#else
+	spin_unlock_irqrestore(&abort_lock, flags);
+#endif	
+#ifdef OLDKERN   
+	save_flags(flags);
+	cli();   
+#else
+ spin_lock_irqsave(&abort_lock, flags);
+#endif   
+     }
+   /*write registers and enable system interrupts */
+   outl (imm_command, IM_CMD_REG(host_index));
+   outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN   
+   restore_flags (flags);
+#else
+   spin_unlock_irqrestore(&abort_lock, flags);
X #endif
+   
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort submitted, waiting for adapter response...\n");
+#endif	
+   while (!cmd->SCp.Status)
+     barrier ();   
+   cmd->scsi_done = saved_done;   
+   /*if abort went well, call saved done, then return success or error */   
+   if (cmd->result == (DID_ABORT << 16))
+     {
+	cmd->result |= DID_ABORT << 16;
+	if (cmd->scsi_done)
+	  (cmd->scsi_done) (cmd);
+	ld(host_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort finished with success.\n");
+#endif	
+	return SCSI_ABORT_SUCCESS;
+     }
+   else
+     {
+	cmd->result |= DID_NO_CONNECT << 16;
+	if (cmd->scsi_done)
+	  (cmd->scsi_done) (cmd);
+	ld(host_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort failed.\n");
+#endif		
+	return SCSI_ABORT_ERROR;
+     }
X }
X 
X /*--------------------------------------------------------------------*/
X 
-int
-ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags)
+int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags)
X {
-  struct Scsi_Host *shpnt = cmd->host;
-  int ticks = IM_RESET_DELAY*HZ;
+   struct Scsi_Host *shpnt;
+   Scsi_Cmnd *cmd_aid;
+   int ticks,i;
+   int host_index;
+   static unsigned long flags;
+ unsigned long imm_command;
+   
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();   
+#else
+   spin_lock_irqsave(&reset_lock, flags);
+#endif   
+   ticks = IM_RESET_DELAY*HZ;
+   shpnt = cmd->host;
+   /* search for the right hostadapter */
+   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+   if (!hosts[host_index])
+     { /* invalid hostadapter descriptor address */
+	if (!local_checking_phase_flag(host_index))
+	  {
+	     cmd->result = DID_NO_CONNECT << 16;
+	     if (cmd->scsi_done)
+	       (cmd->done) (cmd);
+	  }
+	return SCSI_ABORT_SNOOZE;
+     }
X 
-  if (local_checking_phase_flag) {
-    printk("IBM MCA SCSI: unable to reset while checking devices.\n");
-    return SCSI_RESET_SNOOZE;
-  }
-
-  /* issue reset immediate command to subsystem, and wait for interrupt */
-  printk("IBM MCA SCSI: resetting all devices.\n");
-  cli ();
-  reset_status = IM_RESET_IN_PROGRESS;
-  issue_cmd (shpnt, IM_RESET_IMM_CMD, IM_IMM_CMD | 0xf);
-  while (reset_status == IM_RESET_IN_PROGRESS && --ticks) {
-    mdelay(1+999/HZ);
-    barrier();
-  }
-  /* if reset did not complete, just return an error*/
-  if (!ticks) {
-    printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
-           IM_RESET_DELAY);
-    reset_status = IM_RESET_FINISHED_FAIL;
-    return SCSI_RESET_ERROR;
-  }
-
-  /* if reset failed, just return an error */
-  if (reset_status == IM_RESET_FINISHED_FAIL) {
-    printk("IBM MCA SCSI: reset failed.\n");
-    return SCSI_RESET_ERROR;
-  }
+   if (local_checking_phase_flag(host_index))
+     {
+	printk("IBM MCA SCSI: unable to reset while checking devices.\n");
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&reset_lock, flags);
+#endif		
+	return SCSI_RESET_SNOOZE;
+     }
X 
-  /* so reset finished ok - call outstanding done's, and return success */
-  printk ("IBM MCA SCSI: reset completed without error.\n");
-  {
-    int i;
-    for (i = 0; i < MAX_LOG_DEV; i++)
-      {
-        Scsi_Cmnd *cmd = ld[i].cmd;
-        if (cmd && cmd->scsi_done)
-          {
-            ld[i].cmd = 0;
-            cmd->result = DID_RESET;
-            (cmd->scsi_done) (cmd);
-          }
-      }
-  }
-  return SCSI_RESET_SUCCESS;
+   /* issue reset immediate command to subsystem, and wait for interrupt */
+   printk("IBM MCA SCSI: resetting all devices.\n");
+   reset_status(host_index) = IM_RESET_IN_PROGRESS;
+   last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
+   last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+   imm_command = inl(IM_CMD_REG(host_index));
+   imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */
+   imm_command |= (unsigned long)(IM_RESET_IMM_CMD);
+   /* must wait for attention reg not busy */
+   while (1)
+     {
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	  break;
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&reset_lock, flags);
+#endif	
+#ifdef OLDKERN   
+	save_flags(flags);
+	cli();   
+#else
+ spin_lock_irqsave(&reset_lock, flags);
+#endif   
+     }
+   /*write registers and enable system interrupts */
+   outl (imm_command, IM_CMD_REG(host_index));
+   outb (IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
+   /* wait for interrupt finished or intr_stat register to be set, as the
+    * interrupt will not be executed, while we are in here! */
+   while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks
+ && ((inb(IM_INTR_REG(host_index)) & 0x8f)!=0x8f)) {
+      mdelay(1+999/HZ);
+      barrier();
+   }
+   /* if reset did not complete, just return an error*/
+   if (!ticks) {
+      printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
+	     IM_RESET_DELAY);
+ reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+#ifdef OLDKERN   
+      restore_flags(flags);
+#else
+      spin_unlock_irqrestore(&reset_lock, flags);
+#endif   
+      return SCSI_RESET_ERROR;
+   }
+   
+   if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f)
+     { /* analysis done by this routine and not by the intr-routine */
+	if (inb(IM_INTR_REG(host_index))==0xaf)
+	  reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
+	else if (inb(IM_INTR_REG(host_index))==0xcf)
+	  reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+	else /* failed, 4get it */
+	  reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
+	outb (IM_EOI | 0xf, IM_ATTN_REG(host_index));
+     }	
+   
+   /* if reset failed, just return an error */
+   if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
+      printk("IBM MCA SCSI: reset failed.\n");
+#ifdef OLDKERN   
+      restore_flags(flags);
+#else
+      spin_unlock_irqrestore(&reset_lock, flags);
+#endif         
+      return SCSI_RESET_ERROR;
+   }
+   
+   /* so reset finished ok - call outstanding done's, and return success */
+   printk ("IBM MCA SCSI: Reset completed without known error.\n");
+#ifdef OLDKERN   
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&reset_lock, flags);
+#endif      
+   for (i = 0; i < MAX_LOG_DEV; i++)
+     {
+	cmd_aid = ld(host_index)[i].cmd;
+	if (cmd_aid && cmd_aid->scsi_done)
+	  {
+	     ld(host_index)[i].cmd = NULL;
+	     cmd_aid->result = DID_RESET << 16;
+	     (cmd_aid->scsi_done) (cmd_aid);
+	  }
+     }
+   return SCSI_RESET_SUCCESS;
X }
X 
X /*--------------------------------------------------------------------*/
X 
-int 
-ibmmca_biosparam (Disk * disk, kdev_t dev, int *info)
+int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info)
X {
-  info[0] = 64;
-  info[1] = 32;
-  info[2] = disk->capacity / (info[0] * info[1]);
-  if (info[2] >= 1024)
-    {
-      info[0] = 128;
-      info[1] = 63;
-      info[2] = disk->capacity / (info[0] * info[1]);
-      if (info[2] >= 1024)
-	{
-	  info[0] = 255;
-	  info[1] = 63;
-	  info[2] = disk->capacity / (info[0] * info[1]);
-	  if (info[2] >= 1024)
-	    info[2] = 1023;
-	}
-    }
-  return 0;
+   info[0] = 64;
+   info[1] = 32;
+   info[2] = disk->capacity / (info[0] * info[1]);
+   if (info[2] >= 1024)
+     {
+	info[0] = 128;
+	info[1] = 63;
+	info[2] = disk->capacity / (info[0] * info[1]);
+	if (info[2] >= 1024)
+	  {
+	     info[0] = 255;
+	     info[1] = 63;
+	     info[2] = disk->capacity / (info[0] * info[1]);
+	     if (info[2] >= 1024)
+	       info[2] = 1023;
+	  }
+     }
+   return 0;
X }
X 
X /* calculate percentage of total accesses on a ldn */
-static int ldn_access_load(struct Scsi_Host *shpnt, int ldn)
+static int ldn_access_load(int host_index, int ldn)
X {
-   if (IBM_DS.total_accesses == 0) return (0);
-   if (IBM_DS.ldn_access[ldn] == 0) return (0);
-   return (IBM_DS.ldn_access[ldn] * 100) / IBM_DS.total_accesses;
+   if (IBM_DS(host_index).total_accesses == 0) return (0);
+   if (IBM_DS(host_index).ldn_access[ldn] == 0) return (0);
+   return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
X }
X 
X /* calculate total amount of r/w-accesses */
-static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
+static int ldn_access_total_read_write(int host_index)
X {
-   int a = 0;
+   int a;
X    int i;
X    
+   a = 0;
X    for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS.ldn_read_access[i]+IBM_DS.ldn_write_access[i];
+     a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i];
X    return(a);
X }
X 
-static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
+static int ldn_access_total_inquiry(int host_index)
X {
-   int a = 0;
+   int a;
X    int i;
X    
+   a = 0;
X    for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS.ldn_inquiry_access[i];
+     a+=IBM_DS(host_index).ldn_inquiry_access[i];
X    return(a);
X }
X 
-static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
+static int ldn_access_total_modeselect(int host_index)
X {
-   int a = 0;
+   int a;
X    int i;
X    
+   a = 0;
X    for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS.ldn_modeselect_access[i];
+     a+=IBM_DS(host_index).ldn_modeselect_access[i];
X    return(a);
X }
X 
@@ -2186,28 +2489,30 @@
X 		      int hostno, int inout)
X {
X    int len=0;
-   int i,id,lun;
+   int i,id,lun,host_index;
X    struct Scsi_Host *shpnt;
X    unsigned long flags;
X 
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();
+#else
+   spin_lock_irqsave(&proc_lock, flags);
+#endif   
+
X    for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
X    shpnt = hosts[i];
+   host_index = i;
X    if (!shpnt) {
X        len += sprintf(buffer+len, "\nCan't find adapter for host number %d\n", hostno);
X        return len;
X    }
X 
-   save_flags(flags);
-   cli();
-
X    len += sprintf(buffer+len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n",
X 		  IBMMCA_SCSI_DRIVER_VERSION);
X    len += sprintf(buffer+len, " SCSI Access-Statistics:\n");
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   len += sprintf(buffer+len, "               ANSI-SCSI-standard order.: Yes\n");
-#else
-   len += sprintf(buffer+len, "               ANSI-SCSI-standard order.: No\n");
-#endif
+   len += sprintf(buffer+len, "               Device Scanning Order....: %s\n",
+		  (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
X #ifdef CONFIG_SCSI_MULTI_LUN
X    len += sprintf(buffer+len, "               Multiple LUN probing.....: Yes\n");
X #else
@@ -2215,72 +2520,74 @@
X #endif
X    len += sprintf(buffer+len, "               This Hostnumber..........: %d\n",
X 		  hostno);
-   len += sprintf(buffer+len, "               Base I/O-Port............: 0x%lx\n",
-		  IM_CMD_REG);
+   len += sprintf(buffer+len, "               Base I/O-Port............: 0x%x\n",
+		  (unsigned int)(IM_CMD_REG(host_index)));
X    len += sprintf(buffer+len, "               (Shared) IRQ.............: %d\n",
X 		  IM_IRQ);
+   len += sprintf(buffer+len, "               SCSI-command set used....: %s\n",
+		  (bypass_controller) ? "software" : "hardware integrated");
X    len += sprintf(buffer+len, "               Total Interrupts.........: %d\n",
-		  IBM_DS.total_interrupts);
+		  IBM_DS(host_index).total_interrupts);
X    len += sprintf(buffer+len, "               Total SCSI Accesses......: %d\n",
-		  IBM_DS.total_accesses);
+		  IBM_DS(host_index).total_accesses);
X    len += sprintf(buffer+len, "                 Total SCSI READ/WRITE..: %d\n",
-		  ldn_access_total_read_write(shpnt));
+		  ldn_access_total_read_write(host_index));
X    len += sprintf(buffer+len, "                 Total SCSI Inquiries...: %d\n",
-		  ldn_access_total_inquiry(shpnt));
+		  ldn_access_total_inquiry(host_index));
X    len += sprintf(buffer+len, "                 Total SCSI Modeselects.: %d\n",
-		  ldn_access_total_modeselect(shpnt));
-   len += sprintf(buffer+len, "                 Total SCSI other cmds..: %d\n\n",
-		  IBM_DS.total_accesses - ldn_access_total_read_write(shpnt)
-		  - ldn_access_total_modeselect(shpnt)
-		  - ldn_access_total_inquiry(shpnt));
-   
+		  ldn_access_total_modeselect(host_index));
+   len += sprintf(buffer+len, "                 Total SCSI other cmds..: %d\n",
+		  IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
+		  - ldn_access_total_modeselect(host_index)
+		  - ldn_access_total_inquiry(host_index));
+   len += sprintf(buffer+len, "               Total SCSI command fails.: %d\n\n",
+		  IBM_DS(host_index).total_errors);
X    len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n");
X    len += sprintf(buffer+len, "         LDN | Accesses [%%] |   READ    |   WRITE   | ASSIGNMENTS\n");
X    len += sprintf(buffer+len, "        -----|--------------|-----------|-----------|--------------\n");
X    for (i=0; i<=MAX_LOG_DEV; i++)
X       len += sprintf(buffer+len, "         %2X  |    %3d       |  %8d |  %8d | %8d\n",
-		     i, ldn_access_load(shpnt, i), IBM_DS.ldn_read_access[i],
-		     IBM_DS.ldn_write_access[i], IBM_DS.ldn_assignments[i]);
+		     i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i],
+		     IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
X    len += sprintf(buffer+len, "        -----------------------------------------------------------\n\n");
X    
X    len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n");
X    len += sprintf(buffer+len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n",
-		  IBM_DS.total_scsi_devices);
+		  IBM_DS(host_index).total_scsi_devices);
X    len += sprintf(buffer+len, "               Dynamical Assignment necessaray..: %s\n", 
-		  IBM_DS.dyn_flag ? "Yes" : "No ");
+		  IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
X    len += sprintf(buffer+len, "               Next LDN to be assigned..........: 0x%x\n",
-		  next_ldn);
+		  next_ldn(host_index));
X    len += sprintf(buffer+len, "               Dynamical assignments done yet...: %d\n",
-		  IBM_DS.dynamical_assignments);
+		  IBM_DS(host_index).dynamical_assignments);
X 
X    len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n");
X    len += sprintf(buffer+len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
X    len += sprintf(buffer+len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
X    for (id=0; id<=7; id++)
X      {
-	len += sprintf(buffer+len, "    %2d     %2s %2s %2s %2s %2s %2s %2s %2s",
-	       id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]), 
-	       ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]), 
-	       ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]), 
-	       ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
-	
-	len += sprintf(buffer+len, "       %2d     ",id);
+	len += sprintf(buffer+len, "    %2d     ",id);
X 	for (lun=0; lun<8; lun++)
-	  len += sprintf(buffer+len,"%2s ",ti_l(get_ldn[id][lun]));
+	  len += sprintf(buffer+len,"%2s ",ti_p(get_scsi(host_index)[id][lun]));	
+	len += sprintf(buffer+len, "      %2d     ",id);
+	for (lun=0; lun<8; lun++)
+	  len += sprintf(buffer+len,"%2s ",ti_l(get_ldn(host_index)[id][lun]));
X 	len += sprintf(buffer+len,"\n");
X      }
X    
X    len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
X    len += sprintf(buffer+len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
-   len += sprintf(buffer+len, " - = nothing found)\n\n");
+   len += sprintf(buffer+len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
X    
X    *start = buffer + offset;
X    len -= offset;
X    if (len > length) 
X      len = length;
-   
+#ifdef OLDKERN   
X    restore_flags(flags);
-   
+#else
+   spin_unlock_irqrestore(&proc_lock, flags);
+#endif   
X    return len;
X }
X 
@@ -2292,6 +2599,4 @@
X #endif
X 
X /*--------------------------------------------------------------------*/
-
-
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/ibmmca.h linux/drivers/scsi/ibmmca.h
--- v2.2.7/linux/drivers/scsi/ibmmca.h	Tue Feb 17 13:12:47 1998
+++ linux/drivers/scsi/ibmmca.h	Tue May 11 10:36:33 1999
@@ -1,24 +1,37 @@
X #ifndef _IBMMCA_H
X #define _IBMMCA_H
X 
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef ibmmca_header_linux_version
+#define ibmmca_header_linux_version(v,p,s) (((v)<<16)+((p)<<8)+(s))
+#endif
+
X /* 
X  * Low Level Driver for the IBM Microchannel SCSI Subsystem
+ * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver)
X  */
X 
+/* Common forward declarations for all Linux-versions: */
+
X /*services provided to the higher level of Linux SCSI driver */
-int ibmmca_proc_info (char *, char **, off_t, int, int, int);
-int ibmmca_detect (Scsi_Host_Template *);
-int ibmmca_release (struct Scsi_Host *);
-int ibmmca_command (Scsi_Cmnd *);
-int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-int ibmmca_abort (Scsi_Cmnd *);
-int ibmmca_reset (Scsi_Cmnd *, unsigned int);
-int ibmmca_biosparam (Disk *, kdev_t, int *);
+extern int ibmmca_proc_info (char *, char **, off_t, int, int, int);
+extern int ibmmca_detect (Scsi_Host_Template *);
+extern int ibmmca_release (struct Scsi_Host *);
+extern int ibmmca_command (Scsi_Cmnd *);
+extern int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+extern int ibmmca_abort (Scsi_Cmnd *);
+extern int ibmmca_reset (Scsi_Cmnd *, unsigned int);
+extern int ibmmca_biosparam (Disk *, kdev_t, int *);
X 
X /*structure for /proc filesystem */
X extern struct proc_dir_entry proc_scsi_ibmmca;
X 
-/*initialization for Scsi_host_template type */
+#if LINUX_VERSION_CODE >= ibmmca_header_linux_version(2,1,0)
+/* Stuff for Linux >= 2.1.0: */
+/*initialization for Scsi_host_template type (Linux >= 2.1.0) */
X /*
X  * 2/8/98
X  * Note to maintainer of IBMMCA.  Do not change this initializer back to
@@ -28,7 +41,7 @@
X #define IBMMCA {						      \
X           proc_dir:       &proc_scsi_ibmmca,    /*proc_dir*/          \
X 	  proc_info:	  ibmmca_proc_info,     /*proc info fn*/      \
-          name:           "IBMMCA",             /*name*/              \
+          name:           "IBM SCSI-Subsystem", /*name*/              \
X           detect:         ibmmca_detect,        /*detect fn*/         \
X           release:        ibmmca_release,       /*release fn*/        \
X           command:        ibmmca_command,       /*command fn*/        \
@@ -40,9 +53,37 @@
X           this_id:        7,                    /*set by detect*/     \
X           sg_tablesize:   16,                   /*sg_tablesize*/      \
X           cmd_per_lun:    1,                    /*cmd_per_lun*/       \
+          unchecked_isa_dma: 0,                 /*32-Bit Busmaster */ \
X           use_clustering: ENABLE_CLUSTERING     /*use_clustering*/    \
X           }
X 
-#endif /* _IBMMCA_H */
+#else
+/* Stuff for Linux < 2.1.0: */
X 
+/*initialization for Scsi_host_template type (Linux < 2.1.0) */
+#define IBMMCA {                                      \
+          NULL,                 /*next*/              \
+          NULL,                 /*usage_count*/       \
+          &proc_scsi_ibmmca,    /*proc_dir*/          \
+          ibmmca_proc_info,     /*proc info fn*/      \
+          "IBM SCSI-Subsystem", /*name*/              \
+          ibmmca_detect,        /*detect fn*/         \
+          ibmmca_release,       /*release fn*/        \
+          NULL,                 /*info fn*/           \
+          ibmmca_command,       /*command fn*/        \
+          ibmmca_queuecommand,  /*queuecommand fn*/   \
+          ibmmca_abort,         /*abort fn*/          \
+          ibmmca_reset,         /*reset fn*/          \
+          NULL,                 /*slave_attach fn*/   \
+          ibmmca_biosparam,     /*bios fn*/           \
+          16,                   /*can_queue*/         \
+          7,                    /*set by detect*/     \
+          16,                   /*sg_tablesize*/      \
+          1,                    /*cmd_per_lun*/       \
+          0,                    /*present*/           \
+          0,                    /*unchecked_isa_dma*/ \
+          ENABLE_CLUSTERING     /*use_clustering*/    \
+        }
+#endif /* kernelversion selection */
X 
+#endif /* _IBMMCA_H */
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c
--- v2.2.7/linux/drivers/scsi/imm.c	Tue Feb 23 15:21:33 1999
+++ linux/drivers/scsi/imm.c	Fri May  7 10:57:42 1999
@@ -881,6 +881,7 @@
X {
X     imm_struct *tmp = (imm_struct *) data;
X     Scsi_Cmnd *cmd = tmp->cur_cmd;
+    unsigned long flags;
X 
X     if (!cmd) {
X 	printk("IMM: bug in imm_interrupt\n");
@@ -931,8 +932,10 @@
X     if (cmd->SCp.phase > 0)
X 	imm_pb_release(cmd->host->unique_id);
X 
+    spin_lock_irqsave(&io_request_lock, flags);
X     tmp->cur_cmd = 0;
X     cmd->scsi_done(cmd);
+    spin_unlock_irqrestore(&io_request_lock, flags);
X     return;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.2.7/linux/drivers/scsi/megaraid.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/megaraid.c	Thu May  6 23:14:37 1999
@@ -9,7 +9,7 @@
X  *              as published by the Free Software Foundation; either version
X  *              2 of the License, or (at your option) any later version.
X  *
- * Version : 0.96
+ * Version : 1.00
X  * 
X  * Description: Linux device driver for AMI MegaRAID controller
X  *
@@ -73,19 +73,37 @@
X  *
X  * Version 0.96:
X  *     762 fully supported.
+ * Version 0.97:
+ *     Changed megaraid_command to use wait_queue.
+ *     Fixed bug of undesirably detecting HP onboard controllers which
+ *      are disabled.
+ *     
+ * Version 1.00:
+ *     Checks to see if an irq ocurred while in isr, and runs through
+ *        routine again.
+ *     Copies mailbox to temp area before processing in isr
+ *     Added barrier() in busy wait to fix volatility bug
+ *     Uses separate list for freed Scbs, keeps track of cmd state
+ *     Put spinlocks around entire queue function for now...
+ *     Full multi-io commands working stablely without previous problems
+ *     Added skipXX LILO option for Madrona motherboard support
+ *
X  *
X  * BUGS:
X  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
X  *     fails to detect the controller as a pci device on the system.
X  *
+ *     Timeout period for mid scsi layer is too short for
+ *     this controller.  Must be increased or Aborts will occur.
+ *
X  *===================================================================*/
X 
X #define CRLFSTR "\n"
X 
-#include <linux/config.h>
X #include <linux/version.h>
X 
X #ifdef MODULE
+#include <linux/modversions.h>
X #include <linux/module.h>
X 
X #if LINUX_VERSION_CODE >= 0x20100
@@ -213,14 +231,15 @@
X  *
X  *================================================================
X  */
-static int MegaIssueCmd (mega_host_config * megaCfg,
+static int megaIssueCmd (mega_host_config * megaCfg,
X 			 u_char * mboxData,
X 			 mega_scb * scb,
X 			 int intr);
X static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
X 			 u_long * buffer, u_long * length);
X 
-static void mega_runque (void *);
+static int mega_busyWaitMbox(mega_host_config *);
+static void mega_runpendq (mega_host_config *);
X static void mega_rundoneq (void);
X static void mega_cmd_done (mega_host_config *, mega_scb *, int);
X static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
@@ -241,15 +260,34 @@
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 20'
echo 'File patch-2.2.8 is continued in part 21'
echo 21 > _shar_seq_.tmp
#!/bin/sh
# this is part 21 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 21; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X  *
X  *================================================================
X  */
+
+/*  Use "megaraid=skipXX" to prohibit driver from scanning XX scsi id
+     on each channel.  Used for Madrona motherboard, where SAF_TE
+     processor id cannot be scanned */
+static char *megaraid;
+#if LINUX_VERSION_CODE > 0x20100
+#ifdef MODULE
+MODULE_PARM(megaraid, "s");
+#endif
+#endif
+static int skip_id;
+
X static int numCtlrs = 0;
X static mega_host_config *megaCtlrs[12] = {0};
X 
+#if DEBUG
+static u_long maxCmdTime = 0;
+#endif
+
+static mega_scb *pLastScb = NULL;
+
X /* Queue of pending/completed SCBs */
-static mega_scb *qPending = NULL;
X static Scsi_Cmnd *qCompleted = NULL;
X 
+#if SERDEBUG
+volatile static spinlock_t serial_lock;
+#endif
X volatile static spinlock_t mega_lock;
-static struct tq_struct runq = {0, 0, mega_runque, NULL};
X 
X struct proc_dir_entry proc_scsi_megaraid =
X {
@@ -299,10 +337,12 @@
X   int i;
X   long flags;
X 
+  spin_lock_irqsave(&serial_lock,flags);
X   va_start (args, fmt);
X   i = vsprintf (strbuf, fmt, args);
X   ser_puts (strbuf);
X   va_end (args);
+  spin_unlock_irqrestore(&serial_lock,flags);
X 
X   return i;
X }
@@ -329,27 +369,28 @@
X  *
X  *-------------------------------------------------------------------------*/
X 
-/*================================================
- * Initialize SCB structures
- *================================================
+/*=======================
+ * Free a SCB structure
+ *=======================
X  */
-static int initSCB (mega_host_config * megaCfg)
+static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
X {
-  int idx;
+  mega_scb **ppScb;
X 
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    megaCfg->scbList[idx].idx = -1;
-    megaCfg->scbList[idx].flag = 0;
-    megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
-				GFP_ATOMIC | GFP_DMA);
-    if (megaCfg->scbList[idx].sgList == NULL) {
-        printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
-        freeSgList(megaCfg);
-        return -1;
+  /* Unlink from pending queue */
+  for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) {
+    if (*ppScb == pScb) {
+	*ppScb = pScb->next;
+	break;
X     }
-    megaCfg->scbList[idx].SCpnt = NULL;
X   }
-  return 0;
+
+  /* Link back into list */
+  pScb->state = SCB_FREE;
+  pScb->SCpnt = NULL;
+
+  pScb->next     = megaCfg->qFree;
+  megaCfg->qFree = pScb;
X }
X 
X /*===========================
@@ -358,138 +399,134 @@
X  */
X static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
X {
-  int idx;
-  long flags;
-
-  spin_lock_irqsave (&mega_lock, flags);
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].idx < 0) {
+  mega_scb *pScb;
X 
-      /* Set Index and SCB pointer */
-      megaCfg->scbList[idx].idx = idx;
-      spin_unlock_irqrestore (&mega_lock, flags);
-      megaCfg->scbList[idx].flag = 0;
-      megaCfg->scbList[idx].SCpnt = SCpnt;
-      megaCfg->scbList[idx].next = NULL;
+  /* Unlink command from Free List */
+  if ((pScb = megaCfg->qFree) != NULL) {
+    megaCfg->qFree = pScb->next;
+    
+    pScb->isrcount = jiffies;
+    pScb->next  = NULL;
+    pScb->state = SCB_ACTIVE;
+    pScb->SCpnt = SCpnt;
X 
-      return &megaCfg->scbList[idx];
-    }
+    return pScb;
X   }
-  spin_unlock_irqrestore (&mega_lock, flags);
X 
X   printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
X 
X   return NULL;
X }
X 
-/*=======================
- * Free a SCB structure
- *=======================
+/*================================================
+ * Initialize SCB structures
+ *================================================
X  */
-static void freeSCB (mega_scb * scb)
+static int initSCB (mega_host_config * megaCfg)
X {
-  scb->flag = 0;
-  scb->next = NULL;
-  scb->SCpnt = NULL;
-    scb->idx = -1;
+  int idx;
+
+  megaCfg->qFree = NULL;
+  for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) {
+    megaCfg->scbList[idx].idx    = idx;
+    megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
+					   GFP_ATOMIC | GFP_DMA);
+    if (megaCfg->scbList[idx].sgList == NULL) {
+      printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
+      freeSgList(megaCfg);
+      return -1;
+    }
+    
+    if (idx < MAX_COMMANDS) {
+      /* Link to free list */
+      freeSCB(megaCfg, &megaCfg->scbList[idx]);
+    }
+  }
+  return 0;
X }
X 
X /* Run through the list of completed requests */
X static void mega_rundoneq ()
X {
-  mega_host_config *megaCfg;
X   Scsi_Cmnd *SCpnt;
-  char islogical;
X 
X   while (1) {
X     DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
X     if (SCpnt == NULL)
X       return;
X 
-    megaCfg = (mega_host_config *) SCpnt->host->hostdata;
-
-    islogical = (SCpnt->channel == megaCfg->host->max_channel &&
-                 SCpnt->target == 0);
-    if (SCpnt->cmnd[0] == INQUIRY &&
-	((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
-	!islogical) {
-      SCpnt->result = 0xF0;
-    }
-
-    /* Convert result to error */
-    switch (SCpnt->result) {
-    case 0x00:
-    case 0x02:
-      SCpnt->result |= (DID_OK << 16);
-      break;
-    case 0x8:
-      SCpnt->result |= (DID_BUS_BUSY << 16);
-      break;
-    default:
-      SCpnt->result |= (DID_BAD_TARGET << 16);
-      break;
-    }
-
X     /* Callback */
X     callDone (SCpnt);
X   }
X }
X 
-/* Add command to the list of completed requests */
-static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
-{
-  pScb->SCpnt->result = status;
-  ENQUEUE (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-  freeSCB (pScb);
-}
-
-/*----------------------------------------------------
- * Process pending queue list
- *
- * Run as a scheduled task 
- *----------------------------------------------------*/
-static void mega_runque (void *dummy)
+/*
+  Runs through the list of pending requests
+  Assumes that mega_lock spin_lock has been acquired.
+*/
+static void mega_runpendq(mega_host_config *megaCfg)
X {
-  mega_host_config *megaCfg;
X   mega_scb *pScb;
-  long flags;
X 
-  /* Take care of any completed requests */
-  mega_rundoneq ();
+  /* Issue any pending commands to the card */
+  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+    if (pScb->state == SCB_ACTIVE) {
+      megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1);
+    }
+  }
+}
X 
-  DEQUEUE (pScb, mega_scb, qPending, next);
+/* Add command to the list of completed requests */
+static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
+			   int status)
+{
+  int islogical;
+  Scsi_Cmnd *SCpnt;
X 
-  if (pScb) {
-    if (pScb->SCpnt) {
-        TRACE(("NULL SCpnt for idx %d!\n",pScb->idx));
-    }
-    megaCfg = (mega_host_config *) pScb->SCpnt->host->hostdata;
-
-    if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR | PENDING)) {
-      TRACE (("%.08lx %.02x <%d.%d.%d> busy%d isr%d pending%d\n",
-	      pScb->SCpnt->serial_number,
-	      pScb->SCpnt->cmnd[0],
-	      pScb->SCpnt->channel,
-	      pScb->SCpnt->target,
-	      pScb->SCpnt->lun,
-	      megaCfg->mbox->busy,
-	      (megaCfg->flag & IN_ISR) ? 1 : 0,
-	      (megaCfg->flag & PENDING) ? 1 : 0));
-    }
-
-    if (MegaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) {
-      /* We're BUSY... come back later */
-      spin_lock_irqsave (&mega_lock, flags);
-      pScb->next = qPending;
-      qPending = pScb;
-      spin_unlock_irqrestore (&mega_lock, flags);
-
-      if (!(megaCfg->flag & PENDING)) {
-	/* If PENDING, irq will schedule task */
-	queue_task (&runq, &tq_scheduler);
-      }
-    }
+  if (pScb == NULL) {
+	TRACE(("NULL pScb in mega_cmd_done!"));
+	printk("NULL pScb in mega_cmd_done!");
+  }
+
+  SCpnt = pScb->SCpnt;
+  freeSCB(megaCfg, pScb);
+
+  if (SCpnt == NULL) {
+	TRACE(("NULL SCpnt in mega_cmd_done!"));
+	TRACE(("pScb->idx = ",pScb->idx));
+	TRACE(("pScb->state = ",pScb->state));
+	TRACE(("pScb->state = ",pScb->state));
+	printk("Problem...!\n");
+	while(1);
+  }
+
+  islogical = (SCpnt->channel == megaCfg->host->max_channel &&
+	       SCpnt->target == 0);
+  if (SCpnt->cmnd[0] == INQUIRY &&
+      ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
+      !islogical) {
+    status = 0xF0;
+  }
+ 
+  SCpnt->result = 0;  /* clear result; otherwise, success returns corrupt
+                         value */
+
+  /* Convert MegaRAID status to Linux error code */
+  switch (status) {
+  case 0x00: /* SUCCESS */
+  case 0x02: /* ERROR_ABORTED */
+    SCpnt->result |= (DID_OK << 16);
+    break;
+  case 0x8:  /* ERR_DEST_DRIVE_FAILED */
+    SCpnt->result |= (DID_BUS_BUSY << 16);
+    break;
+  default:
+    SCpnt->result |= (DID_BAD_TARGET << 16);
+    break;
X   }
+
+  /* Add Scsi_Command to end of completed queue */
+  ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
X }
X 
X /*-------------------------------------------------------------------
@@ -500,7 +537,8 @@
X  * If NULL is returned, the scsi_done function MUST have been called
X  *
X  *-------------------------------------------------------------------*/
-static mega_scb * mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb * mega_build_cmd (mega_host_config * megaCfg, 
+				  Scsi_Cmnd * SCpnt)
X {
X   mega_scb *pScb;
X   mega_mailbox *mbox;
@@ -508,6 +546,11 @@
X   long seg;
X   char islogical;
X 
+  if (SCpnt == NULL) {
+	printk("NULL SCpnt in mega_build_cmd!\n");
+	while(1);
+  }
+
X   if (SCpnt->cmnd[0] & 0x80)	/* ioctl from megamgr */
X     return mega_ioctl (megaCfg, SCpnt);
X 
@@ -519,6 +562,12 @@
X     return NULL;
X   }
X 
+  if (!islogical && SCpnt->target == skip_id) {
+	SCpnt->result = (DID_BAD_TARGET << 16);
+	callDone (SCpnt);
+	return NULL;
+  }
+
X   /*-----------------------------------------------------
X    *
X    *               Logical drive commands
@@ -738,6 +787,21 @@
X   return (pScb);
X }
X 
+#if DEBUG
+static void showMbox(mega_scb *pScb)
+{
+  mega_mailbox *mbox;
+
+  if (pScb == NULL) return;
+
+  mbox = (mega_mailbox *)pScb->mboxData;
+  printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
+	 pScb->SCpnt->pid, 
+	 mbox->cmd, mbox->cmdid, mbox->numsectors,
+	 mbox->lba, mbox->xferaddr, mbox->logdrv,
+	 mbox->numsgelements);
+}
+#endif
X 
X /*--------------------------------------------------------------------
X  * Interrupt service routine
@@ -745,7 +809,7 @@
X static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
X {
X   mega_host_config    *megaCfg;
-  u_char byte, idx, sIdx;
+  u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
X   u_long dword;
X   mega_mailbox *mbox;
X   mega_scb *pScb;
@@ -753,14 +817,14 @@
X   int qCnt, qStatus;
X 
X   megaCfg = (mega_host_config *) devp;
-  mbox = (mega_mailbox *) megaCfg->mbox;
-
-  if (megaCfg->host->irq == irq) {
+  mbox = (mega_mailbox *)tmpBox;
X 
X #if LINUX_VERSION_CODE >= 0x20100
-    spin_lock_irqsave (&io_request_lock, flags);
+  spin_lock_irqsave (&io_request_lock, flags);
X #endif
X 
+  while (megaCfg->host->irq == irq) {
+
X     spin_lock_irqsave (&mega_lock, flags);
X 
X     if (megaCfg->flag & IN_ISR) {
@@ -769,6 +833,11 @@
X 
X     megaCfg->flag |= IN_ISR;
X 
+    if (mega_busyWaitMbox(megaCfg)) {
+	printk(KERN_WARNING "Error: mailbox busy in isr!\n");
+    }
+
+
X     /* Check if a valid interrupt is pending */
X     if (megaCfg->flag & BOARD_QUARTZ) {
X       dword = RDOUTDOOR (megaCfg);
@@ -776,12 +845,16 @@
X 	/* Spurious interrupt */
X 	megaCfg->flag &= ~IN_ISR;
X 	spin_unlock_irqrestore (&mega_lock, flags);
-#if LINUX_VERSION_CODE >= 0x20100
-        spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
-	return;
+	break;
X       }
X       WROUTDOOR (megaCfg, dword);
+
+      /* Copy to temp location */
+      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+
+      /* Acknowledge interrupt */
+      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+      while (RDINDOOR (megaCfg) & 0x02);
X     }
X     else {
X       byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
@@ -789,71 +862,74 @@
X 	/* Spurious interrupt */
X 	megaCfg->flag &= ~IN_ISR;
X 	spin_unlock_irqrestore (&mega_lock, flags);
-#if LINUX_VERSION_CODE >= 0x20100
-        spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
-	return;
+	break;
X       }
X       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+
+      /* Copy to temp location */
+      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+
+      /* Acknowledge interrupt */
+      CLEAR_INTR (megaCfg->host->io_port);
X     }
X 
X     qCnt = mbox->numstatus;
X     qStatus = mbox->status;
X 
-    if (qCnt > 1) {
-      TRACE (("ISR: Received %d status\n", qCnt))
-	printk (KERN_DEBUG "Got numstatus = %d\n", qCnt);
-    }
-
X     for (idx = 0; idx < qCnt; idx++) {
X       sIdx = mbox->completed[idx];
X       if (sIdx > 0) {
X 	pScb = &megaCfg->scbList[sIdx - 1];
-        /* FVF: let's try to avoid un/locking for no good reason */
-        pScb->SCpnt->result = qStatus;
-        ENQUEUE_NL (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-        freeSCB (pScb);
+
+	/* ASSERT(pScb->state == SCB_ISSUED); */
+
+#if DEBUG
+	if (((jiffies) - pScb->isrcount) > maxCmdTime) {
+	  maxCmdTime = (jiffies) - pScb->isrcount;
+	  printk("cmd time = %u\n", maxCmdTime);
+	}
+#endif
+
+	if (pScb->state == SCB_ABORTED) {
+	  printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount));
+	}
+
+	/* Mark command as completed */
+	mega_cmd_done(megaCfg, pScb, qStatus);
X       }
+
X     }
-    if (megaCfg->flag & BOARD_QUARTZ) {
-      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
-      while (RDINDOOR (megaCfg) & 0x02);
-    }
-    else {
-      CLEAR_INTR (megaCfg->host->io_port);
-    }
+    spin_unlock_irqrestore (&mega_lock, flags);
X 
X     megaCfg->flag &= ~IN_ISR;
-    megaCfg->flag &= ~PENDING;
X 
-    spin_unlock_irqrestore (&mega_lock, flags);
-    mega_runque (NULL);
+    mega_rundoneq();
X 
-#if LINUX_VERSION_CODE >= 0x20100
-    spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
+    /* Loop through any pending requests */
+    spin_lock_irqsave(&mega_lock, flags);
+    mega_runpendq(megaCfg);
+    spin_unlock_irqrestore(&mega_lock,flags);
+  }
X 
-#if 0
-    /* Queue as a delayed ISR routine */
-    queue_task_irq_off (&runq, &tq_immediate);
-    mark_bh (IMMEDIATE_BH);
+#if LINUX_VERSION_CODE >= 0x20100
+  spin_unlock_irqrestore (&io_request_lock, flags);
X #endif
-
-  }
X }
X 
X /*==================================================*/
X /* Wait until the controller's mailbox is available */
X /*==================================================*/
-static int busyWaitMbox (mega_host_config * megaCfg)
+static int mega_busyWaitMbox (mega_host_config * megaCfg)
X {
X   mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
X   long counter;
X 
X   for (counter = 0; counter < 10000; counter++) {
-    udelay (100);
-    if (!mbox->busy)
+    if (!mbox->busy) {
X       return 0;
+    }
+    udelay (100);
+    barrier();
X   }
X   return -1;			/* give up after 1 second */
X }
@@ -868,47 +944,55 @@
X  *   int intr         - if 1, interrupt, 0 is blocking
X  *=====================================================
X  */
-static int MegaIssueCmd (mega_host_config * megaCfg,
+static int megaIssueCmd (mega_host_config * megaCfg,
X 	      u_char * mboxData,
X 	      mega_scb * pScb,
X 	      int intr)
X {
X   mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
-  long flags;
X   u_char byte;
X   u_long cmdDone;
-
-  mboxData[0x1] = (pScb ? pScb->idx + 1 : 0x00);	/* Set cmdid */
+  Scsi_Cmnd *SCpnt;
+  
+  mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0);   /* Set cmdid */
X   mboxData[0xF] = 1;		/* Set busy */
X 
-  spin_lock_irqsave(&mega_lock,flags);
-
-#ifndef CONFIG_MEGARAID_MULTI_IO
-  if (megaCfg->flag & PENDING) {
-     spin_unlock_irqrestore(&mega_lock,flags);
-     return -1;
+#if 0
+  if (intr && mbox->busy) {
+    return 0;
X   }
X #endif
X 
X   /* Wait until mailbox is free */
-  if (busyWaitMbox (megaCfg)) {
-    if (pScb) {
-      TRACE (("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,
-	      pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));
-    } else {
-	TRACE(("pScb NULL in MegaIssueCmd!\n"));
+  while (mega_busyWaitMbox (megaCfg)) {
+    printk("Blocked mailbox!!\n");
+    udelay(1000);
+
+#if DEBUG
+    showMbox(pLastScb);
+#endif
+    
+    /* Abort command */
+    if (pScb == NULL) {
+	printk("NULL pScb in megaIssue\n");
+	TRACE(("NULL pScb in megaIssue\n"));
X     }
-    spin_unlock_irqrestore(&mega_lock,flags);
-    return -1;
+    SCpnt = pScb->SCpnt;
+    freeSCB(megaCfg, pScb);
+
+    SCpnt->result = (DID_ABORT << 16);
+    callDone(SCpnt);
+    return 0;
X   }
+  pLastScb = pScb;
X 
+  
X   /* Copy mailbox data into host structure */
-  memset (mbox, 0, 16);
X   memcpy (mbox, mboxData, 16);
X 
X   /* Kick IO */
-  megaCfg->flag |= PENDING;
X   if (intr) {
+
X     /* Issue interrupt (non-blocking) command */
X     if (megaCfg->flag & BOARD_QUARTZ) {
X       mbox->mraid_poll = 0;
@@ -919,12 +1003,11 @@
X       ENABLE_INTR (megaCfg->host->io_port);
X       ISSUE_COMMAND (megaCfg->host->io_port);
X     }
-    spin_unlock_irqrestore(&mega_lock,flags);
+    pScb->state = SCB_ISSUED;
X   }
X   else {			/* Issue non-ISR (blocking) command */
-
+    disable_irq(megaCfg->host->irq);
X     if (megaCfg->flag & BOARD_QUARTZ) {
-
X       mbox->mraid_poll = 0;
X       mbox->mraid_ack = 0;
X       WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1);
@@ -932,7 +1015,6 @@
X       while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
X       WROUTDOOR (megaCfg, cmdDone);
X 
-      spin_unlock_irqrestore(&mega_lock,flags);
X       if (pScb) {
X 	mega_cmd_done (megaCfg, pScb, mbox->status);
X 	mega_rundoneq ();
@@ -941,8 +1023,6 @@
X       WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
X       while (RDINDOOR (megaCfg) & 0x2);
X 
-      megaCfg->flag &= ~PENDING;
-
X     }
X     else {
X       DISABLE_INTR (megaCfg->host->io_port);
@@ -954,8 +1034,6 @@
X 
X       ENABLE_INTR (megaCfg->host->io_port);
X       CLEAR_INTR (megaCfg->host->io_port);
-      megaCfg->flag &= ~PENDING;
-      spin_unlock_irqrestore(&mega_lock,flags);
X 
X       if (pScb) {
X 	mega_cmd_done (megaCfg, pScb, mbox->status);
@@ -966,6 +1044,11 @@
X       }
X 
X     }
+    enable_irq(megaCfg->host->irq);
+  }
+  while (mega_busyWaitMbox (megaCfg)) {
+    printk("Blocked mailbox on exit!\n");
+    udelay(1000);
X   }
X 
X   return 0;
@@ -1058,6 +1141,7 @@
X   u_long paddr;
X 
X   spin_lock_init (&mega_lock);
+
X   /* Initialize adapter inquiry */
X   paddr = virt_to_bus (megaCfg->mega_buffer);
X   mbox = (mega_mailbox *) mboxData;
@@ -1070,7 +1154,7 @@
X   mbox->xferaddr = paddr;
X 
X   /* Issue a blocking command to the card */
-  MegaIssueCmd (megaCfg, mboxData, NULL, 0);
+  megaIssueCmd (megaCfg, mboxData, NULL, 0);
X 
X   /* Initialize host/local structures with Adapter info */
X   adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer;
@@ -1136,7 +1220,7 @@
X  * Returns data to be displayed in /proc/scsi/megaraid/X
X  *----------------------------------------------------------*/
X int megaraid_proc_info (char *buffer, char **start, off_t offset,
-		    int length, int inode, int inout)
+		    int length, int host_no, int inout)
X {
X   *start = buffer;
X   return 0;
@@ -1150,35 +1234,33 @@
X   struct Scsi_Host *host;
X   u_char pciBus, pciDevFun, megaIrq;
X   u_long megaBase;
-  u_short pciIdx = 0;
+  u_short jdx,pciIdx = 0;
X   u_short numFound = 0;
X 
X #if LINUX_VERSION_CODE < 0x20100
X   while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
-#if 0
-    if (flag & BOARD_QUARTZ) {
-      u_int magic;
-      pcibios_read_config_dword (pciBus, pciDevFun,
-				 PCI_CONF_AMISIG,
-				 &magic);
-      if (magic != AMI_SIGNATURE) {
-        pciIdx++;
-	continue;		/* not an AMI board */
-      }
-    }
-#endif
X 
X #if 0
-    } /* keep auto-indenters happy */
+  } /* keep auto-indenters happy */
X #endif
-
X #else
+  
X   struct pci_dev *pdev = pci_devices;
-
+  
X   while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
X     pciBus = pdev->bus->number;
X     pciDevFun = pdev->devfn;
X #endif
+    if (flag & BOARD_QUARTZ) {
+      u_short magic;
+      pcibios_read_config_word (pciBus, pciDevFun,
+				PCI_CONF_AMISIG,
+				&magic);
+      if (magic != AMI_SIGNATURE) {
+        pciIdx++;
+	continue;		/* not an AMI board */
+      }
+    }
X     printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
X 	    pciVendor,
X 	    pciDev,
@@ -1196,7 +1278,7 @@
X 			      &megaIrq);
X #else
X     megaBase = pdev->base_address[0];
-    megaIrq = pdev->irq;
+    megaIrq  = pdev->irq;
X #endif
X     pciIdx++;
X 
@@ -1214,10 +1296,12 @@
X     megaCfg = (mega_host_config *) host->hostdata;
X     memset (megaCfg, 0, sizeof (mega_host_config));
X 
-    printk (KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
+    printk (" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
X 	    host->host_no, (u_int) megaBase, megaIrq);
X 
X     /* Copy resource info into structure */
+    megaCfg->qPending = NULL;
+    megaCfg->qFree    = NULL;
X     megaCfg->flag = flag;
X     megaCfg->host = host;
X     megaCfg->base = megaBase;
@@ -1248,11 +1332,16 @@
X 
X     mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox));
X     mega_i_query_adapter (megaCfg);
+    
+    for(jdx=0; jdx<MAX_LOGICAL_DRIVES; jdx++) {
+      megaCfg->nReads[jdx] = 0;
+      megaCfg->nWrites[jdx] = 0;
+    }
X 
X     /* Initialize SCBs */
X     if (initSCB (megaCfg)) {
-	scsi_unregister (host);
-	continue;
+      scsi_unregister (host);
+      continue;
X     }
X 
X     numFound++;
@@ -1275,6 +1364,16 @@
X     return 0;
X   }
X #endif
+  skip_id = -1;
+  if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) {
+      if (megaraid[4] != '\0') {
+          skip_id = megaraid[4] - '0';
+          if (megaraid[5] != '\0') {
+              skip_id = (skip_id * 10) + (megaraid[5] - '0');
+          }
+      }
+      skip_id = (skip_id > 15) ? -1 : skip_id;
+  }
X 
X   count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
X   count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
@@ -1299,10 +1398,11 @@
X   memset (mbox, 0, 16);
X   mboxData[0] = 0xA;
X 
-  /* Issue a blocking (interrupts disabled) command to the card */
-  MegaIssueCmd (megaCfg, mboxData, NULL, 0);
+  free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise
+					   extra interrupt is generated */
X 
-  schedule ();
+  /* Issue a blocking (interrupts disabled) command to the card */
+  megaIssueCmd (megaCfg, mboxData, NULL, 0);
X 
X   /* Free our resources */
X   if (megaCfg->flag & BOARD_QUARTZ) {
@@ -1311,9 +1411,7 @@
X   else {
X     release_region (megaCfg->host->io_port, 16);
X   }
-  free_irq (megaCfg->host->irq, megaCfg);	/* Must be freed first, otherwise
X 
-						   extra interrupt is generated */
X   freeSgList(megaCfg);
X   scsi_unregister (pSHost);
X 
@@ -1369,6 +1467,9 @@
X {
X   mega_host_config *megaCfg;
X   mega_scb *pScb;
+  long flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
X 
X   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X 
@@ -1381,15 +1482,38 @@
X 
X   SCpnt->scsi_done = pktComp;
X 
+  /* If driver in abort or reset.. cancel this command */
+  if (megaCfg->flag & IN_ABORT) {
+    SCpnt->result = (DID_ABORT << 16);
+    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+
+    spin_unlock_irqrestore(&mega_lock,flags);
+    return 0;
+  }
+  else if (megaCfg->flag & IN_RESET) {
+    SCpnt->result = (DID_RESET << 16);
+    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+
+    spin_unlock_irqrestore(&mega_lock,flags);
+    return 0;
+  }
+
X   /* Allocate and build a SCB request */
X   if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
X     /* Add SCB to the head of the pending queue */
-    ENQUEUE (pScb, mega_scb, qPending, next);
+    ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next);
X 
-    /* Issue the command to the card */
-    mega_runque (NULL);
+    /* Issue any pending command to the card if not in ISR */
+    if (!(megaCfg->flag & IN_ISR)) {
+      mega_runpendq(megaCfg);
+    }
+    else {
+      printk("IRQ pend...\n");
+    }
X   }
X 
+  spin_unlock_irqrestore(&mega_lock,flags);
+
X   return 0;
X }
X 
@@ -1398,31 +1522,16 @@
X  *----------------------------------------------------------------------*/
X volatile static int internal_done_flag = 0;
X volatile static int internal_done_errcode = 0;
+static struct wait_queue *internal_wait = NULL;
X 
X static void internal_done (Scsi_Cmnd * SCpnt)
X {
X   internal_done_errcode = SCpnt->result;
X   internal_done_flag++;
+  wake_up(&internal_wait);
X }
X 
-/*
- *      This seems dangerous in an SMP environment because
- *      while spinning on internal_done_flag in 2.0.x SMP
- *      no IRQ's will be taken, including those that might
- *      be needed to clear this.
- *
- *      I think this should be using a wait queue ?
- *                              -- AC
- */      
-
-/*
- *      I'll probably fix this in the next version, but
- *      megaraid_command() will never get called since can_queue is set,
- *      except maybe in a *really* old kernel in which case it's very
- *      unlikely they'd be using SMP anyway.  Really this function is
- *      just here for completeness.
- *                              - JLJ
- */
+/* shouldn't be used, but included for completeness */
X 
X int megaraid_command (Scsi_Cmnd * SCpnt)
X {
@@ -1431,8 +1540,9 @@
X   /* Queue command, and wait until it has completed */
X   megaraid_queue (SCpnt, internal_done);
X 
-  while (!internal_done_flag)
-    barrier ();
+  while (!internal_done_flag) {
+	interruptible_sleep_on(&internal_wait);
+  }
X 
X   return internal_done_errcode;
X }
@@ -1443,31 +1553,77 @@
X int megaraid_abort (Scsi_Cmnd * SCpnt)
X {
X   mega_host_config *megaCfg;
-  int idx;
-  long flags;
+  int   rc, idx;
+  long  flags;
+  mega_scb *pScb;
+
+  rc = SCSI_ABORT_SUCCESS;
X 
X   spin_lock_irqsave (&mega_lock, flags);
X 
X   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X 
+  megaCfg->flag |= IN_ABORT;
+
+  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+    if (pScb->SCpnt == SCpnt) {
+      /* Found an aborting command */
+#if DEBUG
+      showMbox(pScb);
+#endif
+
+      printk("Abort: %d %u\n", 
+	     SCpnt->timeout_per_command,
+	     (uint)((jiffies) - pScb->isrcount));
+
+      switch(pScb->state) {
+      case SCB_ABORTED: /* Already aborted */
+	rc = SCSI_ABORT_SNOOZE;
+	break;
+      case SCB_ISSUED: /* Waiting on ISR result */
+	rc = SCSI_ABORT_PENDING;
+	pScb->state = SCB_ABORTED;
+	break;
+      }
+    }
+  }
+
+#if 0
X   TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
-	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+	  SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
X 	  SCpnt->lun));
+  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+    if (pScb->SCpnt == SCpnt) { 
+      ser_printk("** %d<%x>  %c\n", pScb->SCpnt->pid, pScb->idx+1,
+		 pScb->state == SCB_ACTIVE ? 'A' : 'I');
+#if DEBUG
+      showMbox(pScb);
+#endif
+    }
+  }
+#endif
+
X   /*
X    * Walk list of SCBs for any that are still outstanding
X    */
X   for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].idx >= 0) {
+    if (megaCfg->scbList[idx].state != SCB_FREE) {
X       if (megaCfg->scbList[idx].SCpnt == SCpnt) {
-	freeSCB (&megaCfg->scbList[idx]);
+	freeSCB (megaCfg, &megaCfg->scbList[idx]);
X 
-	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-	callDone (SCpnt);
+	SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24);
+	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
X       }
X     }
X   }
+  
+  megaCfg->flag &= ~IN_ABORT;
+
X   spin_unlock_irqrestore (&mega_lock, flags);
-  return SCSI_ABORT_SNOOZE;
+
+  mega_rundoneq();
+
+  return rc;
X }
X 
X /*---------------------------------------------------------------------
@@ -1483,6 +1639,8 @@
X 
X   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
X 
+  megaCfg->flag |= IN_RESET;
+
X   TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
X 	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
X 	  SCpnt->lun));
@@ -1491,14 +1649,21 @@
X    * Walk list of SCBs for any that are still outstanding
X    */
X   for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].idx >= 0) {
+    if (megaCfg->scbList[idx].state != SCB_FREE) {
X       SCpnt = megaCfg->scbList[idx].SCpnt;
-      freeSCB (&megaCfg->scbList[idx]);
-      SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-      callDone (SCpnt);
+      if (SCpnt != NULL) {
+	freeSCB (megaCfg, &megaCfg->scbList[idx]);
+	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
+	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+      }
X     }
X   }
+
+  megaCfg->flag &= ~IN_RESET;
+
X   spin_unlock_irqrestore (&mega_lock, flags);
+
+  mega_rundoneq();
X   return SCSI_RESET_PUNT;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.2.7/linux/drivers/scsi/megaraid.h	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/megaraid.h	Tue May 11 10:36:36 1999
@@ -6,24 +6,23 @@
X #endif
X 
X #define IN_ISR                  0x80000000L
-#define NO_INTR                 0x40000000L
-#define IN_TIMEOUT              0x20000000L
-#define PENDING                 0x10000000L
+#define IN_ABORT                0x40000000L
+#define IN_RESET                0x20000000L
X #define BOARD_QUARTZ            0x08000000L
X 
-#define SCB_ACTIVE 0x1
-#define SCB_WAITQ  0x2
-#define SCB_ISSUED 0x4
-
-#define SCB_FREE                -1
-#define SCB_RESET               -2
-#define SCB_ABORT               -3
-#define SCB_LOCKED              -4
+#define SCB_FREE     0x0
+#define SCB_ACTIVE   0x1
+#define SCB_WAITQ    0x2
+#define SCB_ISSUED   0x3
+#define SCB_COMPLETE 0x4
+#define SCB_ABORTED  0x5
+#define SCB_RESET    0x6
X 
X #define MEGA_CMD_TIMEOUT        10
X 
X #define MAX_SGLIST              17
-#define MAX_COMMANDS            254
+#define MAX_COMMANDS            250
+#define MAX_CMD_PER_LUN         63
X 
X #define MAX_LOGICAL_DRIVES      8
X #define MAX_CHANNEL             5
@@ -99,7 +98,7 @@
X #define PCI_CONF_BASE_ADDR_OFFSET  0x10
X #define PCI_CONF_IRQ_OFFSET        0x3c
X #define PCI_CONF_AMISIG            0xa0
-#define AMI_SIGNATURE              0x11223344
+#define AMI_SIGNATURE              0x3344
X 
X #if LINUX_VERSION_CODE < 0x20100
X #define MEGARAID \
@@ -117,11 +116,11 @@
X     megaraid_reset,                     /* Reset Command Function    */\
X     NULL,                               /* Slave Attach Function     */\
X     megaraid_biosparam,                 /* Disk BIOS Parameters      */\
-    254,                                /* # of cmds that can be\
+    MAX_COMMANDS,                       /* # of cmds that can be\
X                                            outstanding at any time */\
X     7,                                  /* HBA Target ID             */\
X     MAX_SGLIST,                         /* Scatter/Gather Table Size */\
-    64,                                 /* SCSI Commands per LUN     */\
+    MAX_CMD_PER_LUN,                    /* SCSI Commands per LUN     */\
X     0,                                  /* Present                   */\
X     0,                                  /* Default Unchecked ISA DMA */\
X     ENABLE_CLUSTERING }		/* Enable Clustering         */
@@ -138,10 +137,10 @@
X     abort:            megaraid_abort,          /* Abort Command Function    */\
X     reset:            megaraid_reset,          /* Reset Command Function    */\
X     bios_param:       megaraid_biosparam,      /* Disk BIOS Parameters      */\
-    can_queue:        1 /* MAX_COMMANDS */,            /* Can Queue                 */\
+    can_queue:        MAX_COMMANDS,            /* Can Queue                 */\
X     this_id:          7,                       /* HBA Target ID             */\
X     sg_tablesize:     MAX_SGLIST,              /* Scatter/Gather Table Size */\
-    cmd_per_lun:      64,                      /* SCSI Commands per LUN     */\
+    cmd_per_lun:      MAX_CMD_PER_LUN,         /* SCSI Commands per LUN     */\
X     present:          0,                       /* Present                   */\
X     unchecked_isa_dma:0,                       /* Default Unchecked ISA DMA */\
X     use_clustering:   ENABLE_CLUSTERING       /* Enable Clustering         */\
@@ -250,13 +249,14 @@
X typedef struct _mega_scb mega_scb;
X 
X struct _mega_scb {
-    int idx;
-    u_long flag;
-    Scsi_Cmnd *SCpnt;
-    u_char mboxData[16];
-    mega_passthru pthru;
-    mega_sglist *sgList;
-    mega_scb *next;
+    int            idx;
+    u_long         state;
+    u_long         isrcount;
+    u_char         mboxData[16];
+    mega_passthru  pthru;
+    Scsi_Cmnd     *SCpnt;
+    mega_sglist   *sgList;
+    mega_scb      *next;
X };
X 
X /* Per-controller data */
@@ -264,8 +264,12 @@
X     u_char numldrv;
X     u_long flag;
X     u_long base;
+ 
+    mega_scb *qFree;
+    mega_scb *qPending;
X 
-    struct tq_struct megaTq;
+  u_long nReads[MAX_LOGICAL_DRIVES];
+  u_long nWrites[MAX_LOGICAL_DRIVES];
X 
X     /* Host adapter parameters */
X     u_char fwVer[7];
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.2.7/linux/drivers/scsi/ppa.c	Mon Mar 29 11:09:11 1999
+++ linux/drivers/scsi/ppa.c	Fri May  7 10:57:42 1999
@@ -741,6 +741,7 @@
X {
X     ppa_struct *tmp = (ppa_struct *) data;
X     Scsi_Cmnd *cmd = tmp->cur_cmd;
+    unsigned long flags;
X 
X     if (!cmd) {
X 	printk("PPA: bug in ppa_interrupt\n");
@@ -792,7 +793,10 @@
X 	ppa_pb_release(cmd->host->unique_id);
X 
X     tmp->cur_cmd = 0;
+    
+    spin_lock_irqsave(&io_request_lock, flags);
X     cmd->scsi_done(cmd);
+    spin_unlock_irqrestore(&io_request_lock, flags);
X     return;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.2.7/linux/drivers/scsi/scsi.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/scsi/scsi.c	Thu Apr 29 11:53:41 1999
@@ -1926,10 +1926,12 @@
X     SDpnt->device_queue = NULL;
X 
X     for(j=0;j<SDpnt->queue_depth;j++){
-      SCpnt = (Scsi_Cmnd *)
+        SCpnt = (Scsi_Cmnd *)
X               scsi_init_malloc(sizeof(Scsi_Cmnd),
X                                GFP_ATOMIC |
X                                (host->unchecked_isa_dma ? GFP_DMA : 0));
+	if (NULL == SCpnt)
+	    break; /* If not, the next line will oops ... */
X         memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
X 	SCpnt->host                      = host;
X 	SCpnt->device                    = SDpnt;
@@ -1951,6 +1953,12 @@
X 	SDpnt->device_queue              = SCpnt;
X         SCpnt->state                     = SCSI_STATE_UNUSED;
X         SCpnt->owner                     = SCSI_OWNER_NOBODY;
+    }
+    if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */
+	printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n",
+	       SDpnt->queue_depth, j);
+	SDpnt->queue_depth = j;
+	/* Still problem if 0==j , continue anyway ... */
X     }
X     SDpnt->has_cmdblocks = 1;
X }
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.2.7/linux/drivers/scsi/scsi_ioctl.c	Wed Sep  9 14:51:09 1998
+++ linux/drivers/scsi/scsi_ioctl.c	Thu Apr 29 11:53:41 1999
@@ -131,15 +131,16 @@
X 	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
X 	    break;
X 	case NOT_READY: /* This happens if there is no disc in drive */
-	    if(dev->removable){
+	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
X 		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
X 		break;
-	    };
+	    }
X 	case UNIT_ATTENTION:
X 	    if (dev->removable){
X 		dev->changed = 1;
X 		SCpnt->result = 0; /* This is no longer considered an error */
-		printk(KERN_INFO "Disc change detected.\n");
+		/* gag this error, VFS will log it anyway /axboe */
+		/* printk(KERN_INFO "Disc change detected.\n"); */
X 		break;
X 	    };
X 	default: /* Fall through for non-removable media */
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.2.7/linux/drivers/scsi/sd.c	Tue Feb 23 15:21:34 1999
+++ linux/drivers/scsi/sd.c	Thu Apr 29 11:53:41 1999
@@ -719,6 +719,12 @@
X  	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
X  	    goto repeat;
X  	}
+    if (rscsi_disks[dev].sector_size == 4096) 
+	if((block & 7) || (SCpnt->request.nr_sectors & 7)) {
+	    printk("sd.cBad block number/count requested");
+	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+	    goto repeat;
+	}
X      
X     switch (SCpnt->request.cmd)
X     {
@@ -984,6 +990,13 @@
X 
X     cmd[1] = (SCpnt->lun << 5) & 0xe0;
X 
+     if (rscsi_disks[dev].sector_size == 4096){
+	if(block & 7) panic("sd.c:Bad block number requested");
+	if(this_count & 7) panic("sd.c:Bad block number requested");
+	block = block >> 3;
+	this_count = block >> 3;
+     }
+
X      if (rscsi_disks[dev].sector_size == 2048){
X  	if(block & 3) panic("sd.c:Bad block number requested");
X  	if(this_count & 3) panic("sd.c:Bad block number requested");
@@ -1335,6 +1348,7 @@
X 	if (rscsi_disks[i].sector_size != 512 &&
X 	    rscsi_disks[i].sector_size != 1024 &&
X 	    rscsi_disks[i].sector_size != 2048 &&
+	    rscsi_disks[i].sector_size != 4096 &&
X 	    rscsi_disks[i].sector_size != 256)
X 	{
X 	    printk ("%s : unsupported sector size %d.\n",
@@ -1394,6 +1408,8 @@
X 		nbuff, hard_sector, rscsi_disks[i].capacity,
X                 mb, sz_quot, sz_rem);
X     }
+	if(rscsi_disks[i].sector_size == 4096)
+	    rscsi_disks[i].capacity <<= 3;
X 	if(rscsi_disks[i].sector_size == 2048)
X 	    rscsi_disks[i].capacity <<= 2;  /* Change into 512 byte sectors */
X 	if(rscsi_disks[i].sector_size == 1024)
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.2.7/linux/drivers/scsi/sg.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/sg.c	Fri May  7 11:05:30 1999
@@ -16,7 +16,7 @@
X  *
X  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
X  */
- static char * sg_version_str = "Version: 2.1.31 (990327)";
+ static char * sg_version_str = "Version: 2.1.32 (990501)";
X /*
X  *  D. P. Gilbert (dgil...@interlog.com, do...@triode.net.au)
X  *      - scatter list logic replaces previous large atomic SG_BIG_BUFF
@@ -69,8 +69,9 @@
X 
X int sg_big_buff = SG_SCATTER_SZ;  /* sg_big_buff is ro through sysctl */
X /* N.B. This global is here to keep existing software happy. It now holds
-   the size of the "first buffer" of the most recent sucessful sg_open(). */
-/* Only available when 'sg' compiled into kernel (rather than a module). */
+   the size of the "first buffer" of the most recent sucessful sg_open(). 
+   Only available when 'sg' compiled into kernel (rather than a module). 
+   This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */
X 
X #define SG_SECTOR_SZ 512
X #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -146,6 +147,7 @@
X     char closed;        /* 1 -> fd closed but request(s) outstanding */
X     char my_mem_src;    /* heap whereabouts of this sg_fb object */
X     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
+    char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
X } Sg_fd; /* around 1192 bytes long on i386 */
X 
X typedef struct sg_device /* holds the state of each scsi generic device */
@@ -173,7 +175,7 @@
X static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, 
X                             int * retSzp);
X static void sg_low_free(char * buff, int size, int mem_src);
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);
+static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved);
X static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
X static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
X static Sg_request * sg_add_request(Sg_fd * sfp);
@@ -240,11 +242,14 @@
X     if (! sdp->headfp) { /* no existing opens on this device */
X         sdp->sgdebug = 0;
X         sdp->sg_tablesize = sdp->device->host->sg_tablesize;
-        sdp->merge_fd = SG_DEF_MERGE_FD;
+        sdp->merge_fd = 0;   /* A little tricky if SG_DEF_MERGE_FD set */
X     }
-    if ((sfp = sg_add_sfp(sdp, dev))) {
+    if ((sfp = sg_add_sfp(sdp, dev, O_RDWR == (flags & O_ACCMODE)))) {
+        filp->private_data = sfp;
+#if SG_DEF_MERGE_FD
X         if (0 == sdp->merge_fd)
-            filp->private_data = sfp;
+            sdp->merge_fd = 1;
+#endif
X     }
X     else {
X         if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */
@@ -322,11 +327,12 @@
X             return -ERESTARTSYS;
X         srp = sg_get_request(sfp, req_pack_id);
X     }
-    srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
+    if (2 != sfp->underrun_flag)
+        srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
X 
X     /* Now copy the result back to the user buffer.  */
X     if (count >= size_sg_header) {
-        copy_to_user(buf, &srp->header, size_sg_header);
+        __copy_to_user(buf, &srp->header, size_sg_header);
X         buf += size_sg_header;
X         if (count > srp->header.reply_len)
X             count = srp->header.reply_len;
@@ -371,7 +377,7 @@
X         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
X 
X     if ((k = verify_area(VERIFY_READ, buf, count)))
-        return k;
+        return k;  /* protects following copy_from_user()s + get_user()s */
X /* The minimum scsi command length is 6 bytes.  If we get anything
X  * less than this, it is clearly bogus.  */
X     if (count < (size_sg_header + 6))
@@ -382,10 +388,10 @@
X         SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n"));
X         return -EDOM;
X     }
-    copy_from_user(&srp->header, buf, size_sg_header);
+    __copy_from_user(&srp->header, buf, size_sg_header); 
X     buf += size_sg_header;
X     srp->header.pack_len = count;
-    get_user(opcode, buf);
+    __get_user(opcode, buf);
X     cmd_size = COMMAND_SIZE(opcode);
X     if ((opcode >= 0xc0) && srp->header.twelve_byte) 
X         cmd_size = 12;
@@ -427,7 +433,7 @@
X     SCpnt->sense_buffer[0] = 0;
X     SCpnt->cmd_len = cmd_size;
X     /* Now copy the SCSI command from the user's address space.  */
-    copy_from_user(cmnd, buf, cmd_size);
+    __copy_from_user(cmnd, buf, cmd_size);
X 
X /* Set the LUN field in the command structure.  */
X     cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
@@ -439,11 +445,10 @@
X     SCpnt->use_sg = srp->data.use_sg;
X     SCpnt->sglist_len = srp->data.sglist_len;
X     SCpnt->bufflen = srp->data.bufflen;
-    SCpnt->underflow = srp->data.bufflen;
-/* Not many drivers look at this:
-        aic7xxx driver gives DID_RETRY_COMMAND on underrun
-        seagate comments out its underrun checking code, and the rest ...
-*/
+    if (1 == sfp->underrun_flag)
+        SCpnt->underflow = srp->data.bufflen;
+    else
+        SCpnt->underflow = 0;
X     SCpnt->buffer = srp->data.buffer;
X     srp->data.use_sg = 0;
X     srp->data.sglist_len = 0;
@@ -479,14 +484,10 @@
X     switch(cmd_in)
X     {
X     case SG_SET_TIMEOUT:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
X         return get_user(sfp->timeout, (int *)arg);
X     case SG_GET_TIMEOUT:
X         return sfp->timeout; /* strange ..., for backward compatibility */
X     case SG_SET_FORCE_LOW_DMA:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
X         result = get_user(val, (int *)arg);
X         if (result) return result;
X         if (val) {
@@ -503,28 +504,23 @@
X             sfp->low_dma = sdp->device->host->unchecked_isa_dma;
X         return 0;
X     case SG_GET_LOW_DMA:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user((int)sfp->low_dma, (int *)arg);
-        return 0;
+        return put_user((int)sfp->low_dma, (int *)arg);
X     case SG_GET_SCSI_ID:
X         result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(Sg_scsi_id));
X         if (result) return result;
X         else {
X             Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg;
-            put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
-            put_user((int)sdp->device->channel, &sg_idp->channel);
-            put_user((int)sdp->device->id, &sg_idp->scsi_id);
-            put_user((int)sdp->device->lun, &sg_idp->lun);
-            put_user((int)sdp->device->type, &sg_idp->scsi_type);
-            put_user(0, &sg_idp->unused1);
-            put_user(0, &sg_idp->unused2);
-            put_user(0, &sg_idp->unused3);
+            __put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
+            __put_user((int)sdp->device->channel, &sg_idp->channel);
+            __put_user((int)sdp->device->id, &sg_idp->scsi_id);
+            __put_user((int)sdp->device->lun, &sg_idp->lun);
+            __put_user((int)sdp->device->type, &sg_idp->scsi_type);
+            __put_user(0, &sg_idp->unused1);
+            __put_user(0, &sg_idp->unused2);
+            __put_user(0, &sg_idp->unused3);
X             return 0;
X         }
X     case SG_SET_FORCE_PACK_ID:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
X         result = get_user(val, (int *)arg);
X         if (result) return result;
X         sfp->force_packid = val ? 1 : 0;
@@ -535,16 +531,14 @@
X         srp = sfp->headrp;
X         while (srp) {
X             if (! srp->my_cmdp) {
-                put_user(srp->header.pack_id, (int *)arg);
+                __put_user(srp->header.pack_id, (int *)arg);
X                 return 0;
X             }
X             srp = srp->nextrp;
X         }
-        put_user(-1, (int *)arg);
+        __put_user(-1, (int *)arg);
X         return 0;
X     case SG_GET_NUM_WAITING:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
X         srp = sfp->headrp;
X         val = 0;
X         while (srp) {
@@ -552,36 +546,25 @@
X                 ++val;
X             srp = srp->nextrp;
X         }
-        put_user(val, (int *)arg);
-        return 0;
+        return put_user(val, (int *)arg);
X     case SG_GET_SG_TABLESIZE:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user(sdp->sg_tablesize, (int *)arg);
-        return 0;
+        return put_user(sdp->sg_tablesize, (int *)arg);
X     case SG_SET_RESERVED_SIZE:
X         /* currently ignored, future extension */
X         if (O_RDWR != (filp->f_flags & O_ACCMODE))
X             return -EACCES;
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
+        result = get_user(val, (int *)arg);
X         if (result) return result;
+        /* logic should go here */
X         return 0;
X     case SG_GET_RESERVED_SIZE:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user(sfp->fb_size, (int *)arg);
-        return 0;
+        return put_user(sfp->fb_size, (int *)arg);
X     case SG_GET_MERGE_FD:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user((int)sdp->merge_fd, (int *)arg);
-        return 0;
+        return put_user((int)sdp->merge_fd, (int *)arg);
X     case SG_SET_MERGE_FD:
X         if (O_RDWR != (filp->f_flags & O_ACCMODE))
X             return -EACCES; /* require write access since effect wider
X                                then just this fd */
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
X         result = get_user(val, (int *)arg);
X         if (result) return result;
X         val = val ? 1 : 0;
@@ -591,17 +574,19 @@
X         sdp->merge_fd = val;
X         return 0;
X     case SG_SET_COMMAND_Q:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
X         result = get_user(val, (int *)arg);
X         if (result) return result;
X         sfp->cmd_q = val ? 1 : 0;
X         return 0;
X     case SG_GET_COMMAND_Q:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+        return put_user((int)sfp->cmd_q, (int *)arg);
+    case SG_SET_UNDERRUN_FLAG:
+        result = get_user(val, (int *)arg);
X         if (result) return result;
-        put_user((int)sfp->cmd_q, (int *)arg);
+        sfp->underrun_flag = val;
X         return 0;
+    case SG_GET_UNDERRUN_FLAG:
+        return put_user((int)sfp->underrun_flag, (int *)arg);
X     case SG_EMULATED_HOST:
X         return put_user(sdp->device->host->hostt->emulated, (int *)arg);
X     case SCSI_IOCTL_SEND_COMMAND:
@@ -613,8 +598,6 @@
X                                dangerous */
X         return scsi_ioctl_send_command(sdp->device, (void *)arg);
X     case SG_SET_DEBUG:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
X         result = get_user(val, (int *)arg);
X         if (result) return result;
X         sdp->sgdebug = (char)val;
@@ -625,6 +608,8 @@
X         return 0;
X     case SCSI_IOCTL_GET_IDLUN:
X     case SCSI_IOCTL_GET_BUS_NUMBER:
+    case SCSI_IOCTL_PROBE_HOST:
+    case SG_GET_TRANSFORM:
X         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
X     default:
X         if (O_RDWR != (filp->f_flags & O_ACCMODE))
@@ -698,6 +683,7 @@
X     sdp = &sg_dev_arr[dev];
X     if (NULL == sdp->device)
X         return; /* Get out of here quick ... */
+
X     sfp = sdp->headfp;
X     while (sfp) {
X         srp = sfp->headrp;
@@ -721,6 +707,8 @@
X     srp->data.sglist_len = SCpnt->sglist_len;
X     srp->data.bufflen = SCpnt->bufflen;
X     srp->data.buffer = SCpnt->buffer;
+    if (2 == sfp->underrun_flag)
+        srp->header.pack_len = SCpnt->underflow;
X     sg_clr_scpnt(SCpnt);
X     srp->my_cmdp = NULL;
X 
@@ -755,7 +743,7 @@
X        * underrun or overrun should signal an error.  Until that can be
X        * implemented, this kludge allows for returning useful error values
X        * except in cases that return DID_ERROR that might be due to an
-       * underrun. [Underrun on advansys adapter yields DID_ABORT -dpg]  */
+       * underrun. */
X       if (SCpnt->sense_buffer[0] == 0 &&
X           status_byte(SCpnt->result) == GOOD)
X           srp->header.result = 0;
@@ -887,8 +875,9 @@
X             printk(">> Following FD has NULL parent pointer ???\n");
X         printk("   FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n",
X                k, fp->timeout, fp->fb_size, (int)fp->cmd_q);
-        printk("   low_dma=%d, force_packid=%d, closed=%d\n",
-               (int)fp->low_dma, (int)fp->force_packid, (int)fp->closed);
+        printk("   low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n",
+               (int)fp->low_dma, (int)fp->force_packid, 
+               (int)fp->underrun_flag, (int)fp->closed);
X         srp = fp->headrp;
X         if (NULL == srp)
X             printk("     No requests active\n");
@@ -1002,7 +991,7 @@
X     sdp->generic_wait = NULL;
X     sdp->headfp= NULL;
X     sdp->exclude = 0;
-    sdp->merge_fd = 0;
+    sdp->merge_fd = 0;  /* Cope with SG_DEF_MERGE_FD on open */
X     sdp->sgdebug = 0;
X     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
X     sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
@@ -1120,7 +1109,7 @@
X     if ((blk_size < 0) || (! srp))
X         return -EFAULT;
X     
-    SCSI_LOG_TIMEOUT(4, printk("sg build: m_b_s=%d, num_write_xfer=%d\n", 
+    SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n", 
X                                   max_buff_size, num_write_xfer)); 
X     if (0 == blk_size)
X         ++blk_size;             /* don't know why */
@@ -1139,7 +1128,7 @@
X             srp->data.mem_src = mem_src;
X             srp->data.b_malloc_len = blk_size;
X             if (inp && (num_write_xfer > 0))
-                copy_from_user(srp->data.buffer, inp, num_write_xfer);
+                __copy_from_user(srp->data.buffer, inp, num_write_xfer);
X             return 0;
X         }
X     }
@@ -1185,17 +1174,17 @@
X             }
X             sclp->address = p;
X             sclp->length = ret_sz;
-            sclp->alt_address = (char *)mem_src;
+            sclp->alt_address = (char *)(long)mem_src;
X             
X             if(inp && (num_write_xfer > 0)) {
X                 num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz;
-                copy_from_user(sclp->address, inp, num);
+                __copy_from_user(sclp->address, inp, num);
X                 num_write_xfer -= num;
X                 inp += num;
X             }
X             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_build: k=%d, a=0x%x, len=%d, ms=%d\n", 
-                k, (int)sclp->address, ret_sz, (int)sclp->alt_address));
+                printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                k, sclp->address, ret_sz, mem_src));
X         } /* end of for loop */
X         srp->data.use_sg = k;
X         SCSI_LOG_TIMEOUT(5, 
@@ -1224,20 +1213,20 @@
X             if (num_read_xfer > 0) {
X                 num = (int)sclp->length;
X                 if (num > num_read_xfer) {
-                    copy_to_user(outp, sclp->address, num_read_xfer);
+                    __copy_to_user(outp, sclp->address, num_read_xfer);
X                     outp += num_read_xfer;
X                     num_read_xfer = 0;
X                 }
X                 else {
-                    copy_to_user(outp, sclp->address, num);
+                    __copy_to_user(outp, sclp->address, num);
X                     outp += num;
X                     num_read_xfer -= num;
X                 }
X             }
-            mem_src = (int)sclp->alt_address;
+            mem_src = (int)(long)sclp->alt_address;
X             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_undo_rem: k=%d, a=0x%x, len=%d, ms=%d\n", 
-                       k, (int)sclp->address, sclp->length, mem_src));
+                printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                       k, sclp->address, sclp->length, mem_src));
X             sg_free(srp, sclp->address, sclp->length, mem_src);
X         }
X         sg_free(srp, srp->data.buffer, srp->data.sglist_len, 
@@ -1245,13 +1234,13 @@
X     }
X     else {
X         if (num_read_xfer > 0) 
-            copy_to_user(outp, srp->data.buffer, num_read_xfer);
+            __copy_to_user(outp, srp->data.buffer, num_read_xfer);
X         sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, 
X                 srp->data.mem_src);
X     }
X     if (0 == sg_remove_request(srp->parentfp, srp)) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=%d not found\n", 
-                                   (int)srp));
+        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", 
+                                   srp));
X     }
X     return 0;
X }
@@ -1336,7 +1325,7 @@
X     return 0;
X }
X 
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev)
+static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
X {
X     Sg_fd * sfp;
X 
@@ -1357,8 +1346,12 @@
X     sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
X                    sdp->device->host->unchecked_isa_dma : 1;
X     sfp->cmd_q = SG_DEF_COMMAND_Q;
-    sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, 
-                                 SG_HEAP_PAGE, &sfp->fb_size);
+    sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
+    if (get_reserved)
+        sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, 
+                                     SG_HEAP_PAGE, &sfp->fb_size);
+    else
+        sfp->fst_buf = NULL;
X     if (! sfp->fst_buf)
X         sfp->fb_size = 0;
X     sfp->parentdp = sdp;
@@ -1371,10 +1364,10 @@
X         pfp->nextfp = sfp;
X     }
X     sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%x, m_s=%d\n",
-                               (int)sfp, (int)sfp->my_mem_src));
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   fb_sz=%d, fst_buf=0x%x\n",
-                               sfp->fb_size, (int)sfp->fst_buf));
+    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
+                               sfp, (int)sfp->my_mem_src));
+    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   fb_sz=%d, fst_buf=0x%p\n",
+                               sfp->fb_size, sfp->fst_buf));
X     return sfp;
X }
X 
@@ -1416,13 +1409,13 @@
X                 prev_fp = fp;
X             }
X         }
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%x\n",
-                 sfp->fb_size, (int)sfp->fst_buf));
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%p\n",
+                 sfp->fb_size, sfp->fst_buf));
X         sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
X         sfp->parentdp = NULL;
X         sfp->fst_buf = NULL;
X         sfp->fb_size = 0;
-    SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%x\n", (int)sfp));
+    SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%p\n", sfp));
X         sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
X         res = 1;
X     }
@@ -1573,8 +1566,8 @@
X         }
X         if (resp) *mem_srcp = l_ms;
X     }
-    SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%x\n", 
-                               size, *mem_srcp, (int)resp));
+    SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n", 
+                               size, *mem_srcp, resp));
X     return resp;
X }
X 
@@ -1598,8 +1591,8 @@
X         free_pages((unsigned long)buff, order);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 21'
echo 'File patch-2.2.8 is continued in part 22'
echo 22 > _shar_seq_.tmp
#!/bin/sh
# this is part 22 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 22; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X     }
X     else
-        printk("sg_low_free: bad mem_src=%d, buff=0x%x, rqSz=%df\n", 
-               mem_src, (int)buff, size);
+        printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n", 
+               mem_src, buff, size);
X }
X 
X static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
@@ -1607,7 +1600,7 @@
X     Sg_fd * sfp = srp->parentfp;
X 
X     SCSI_LOG_TIMEOUT(6, 
-        printk("sg_free: buff=0x%x, size=%d\n", (int)buff, size));
+        printk("sg_free: buff=0x%p, size=%d\n", buff, size));
X     if ((! sfp) || (! buff) || (size <= 0))
X         ;
X     else if (sfp->fst_buf == buff) {
@@ -1624,5 +1617,7 @@
X     SCpnt->sglist_len = 0;
X     SCpnt->bufflen = 0;
X     SCpnt->buffer = NULL;
+    SCpnt->underflow = 0;
+    SCpnt->request.rq_dev = MKDEV(0, 0);  /* "sg" _disowns_ command blk */
X }
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.2.7/linux/drivers/scsi/sr_ioctl.c	Wed Mar 10 15:29:47 1999
+++ linux/drivers/scsi/sr_ioctl.c	Mon May 10 13:01:21 1999
@@ -82,7 +82,8 @@
X 	switch(SCpnt->sense_buffer[2] & 0xf) {
X 	case UNIT_ATTENTION:
X 	    scsi_CDs[target].device->changed = 1;
-	    printk(KERN_INFO "sr%d: disc change detected.\n", target);
+	    if (!quiet)
+	    	printk(KERN_INFO "sr%d: disc change detected.\n", target);
X 	    if (retries++ < 10)
X 		goto retry;
X 	    err = -ENOMEDIUM;
@@ -105,12 +106,13 @@
X 		    spin_unlock_irqrestore(&io_request_lock, flags);
X                     goto retry;
X 		} else {
-		    /* 20 secs are enouth? */
+		    /* 20 secs are enough? */
X 		    err = -ENOMEDIUM;
X 		    break;
X 		}
X             }
-            printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n",target);
+	    if (!quiet)
+            	printk(KERN_INFO "sr%d: CDROM not ready.  Make sure there is a disc in the drive.\n",target);
X #ifdef DEBUG
X             print_sense("sr", SCpnt);
X #endif
@@ -120,9 +122,11 @@
X             if (!quiet)
X 		printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL "
X 		       "REQUEST.\n", target);
-            if (SCpnt->sense_buffer[12] == 0x20 &&
+            if ((SCpnt->sense_buffer[12] == 0x20 ||
+	        SCpnt->sense_buffer[12] == 0x24) &&
X                 SCpnt->sense_buffer[13] == 0x00) {
X                 /* sense: Invalid command operation code */
+                /* or Invalid field in cdb */
X                 err = -EDRIVE_CANT_DO_THIS;
X             } else {
X                 err = -EINVAL;
@@ -408,7 +412,7 @@
X         spin_unlock_irqrestore(&io_request_lock, flags);
X 	if(!buffer) return -ENOMEM;
X 	
-	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
+	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
X 	
X 	tochdr->cdth_trk0 = buffer[2];
X 	tochdr->cdth_trk1 = buffer[3];
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.2.7/linux/drivers/scsi/sr_vendor.c	Wed May 20 19:10:40 1998
+++ linux/drivers/scsi/sr_vendor.c	Mon May 10 13:01:21 1999
@@ -175,7 +175,7 @@
X 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
X 		cmd[8] = 12;
X 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);	
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);
X 		if (rc != 0)
X 			break;
X 		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
@@ -199,7 +199,7 @@
X 		cmd[0] = 0xde;
X 		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
X 		cmd[2] = 0xb0;
-		rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 0);
+		rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1);
X 		if (rc != 0)
X 			break;
X 		if (buffer[14] != 0 && buffer[14] != 0xb0) {
@@ -223,7 +223,7 @@
X 		memset(cmd,0,12);
X 		cmd[0] = 0xc7;
X 		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
-		rc = sr_do_ioctl(minor, cmd, buffer, 4, 0);
+		rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
X 		if (rc == -EINVAL) {
X 			printk(KERN_INFO "sr%d: Hmm, seems the drive "
X 			       "doesn't support multisession CD's\n",minor);
@@ -248,7 +248,7 @@
X 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
X 		cmd[8] = 0x04;
X 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 0);
+		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1);
X 		if (rc != 0) {
X 			break;
X 		}
@@ -263,7 +263,7 @@
X 		cmd[6] = rc & 0x7f;  /* number of last session */
X 		cmd[8] = 0x0c;
X 		cmd[9] = 0x40;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);	
+		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1);	
X 		if (rc != 0) {
X 			break;
X 		}
diff -u --recursive --new-file v2.2.7/linux/drivers/sound/ad1816.c linux/drivers/sound/ad1816.c
--- v2.2.7/linux/drivers/sound/ad1816.c	Mon Jan 25 17:44:34 1999
+++ linux/drivers/sound/ad1816.c	Mon May 10 13:01:21 1999
@@ -32,10 +32,10 @@
X 
X -------------------------------------------------------------------------------
X 
-version: 1.2
-cvs: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.28 1999/01/16 19:01:36 tek Exp $
+version: 1.3
+cvs: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $
X status: experimental
-date: 1999/01/16
+date: 1999/4/18
X 
X Changes:
X 	Oleg Drokin: Some cleanup of load/unload functions.    1998/11/24
@@ -44,6 +44,13 @@
X 	some argument checks added                             1998/11/30
X 
X 	Thorsten Knabe: Buggy isa bridge workaround added      1999/01/16
+	
+	David Moews/Thorsten Knabe: Introduced options 
+	parameter. Added slightly modified patch from 
+	David Moews to disable dsp audio sources by setting 
+	bit 0 of options parameter. This seems to be
+	required by some Aztech/Newcom SC-16 cards.            1999/04/18
+	
X */
X 
X #include <linux/config.h>
@@ -100,6 +107,8 @@
X 
X static int  ad1816_clockfreq=33000;
X 
+static int options=0;
+
X /* for backward mapping of irq to sound device */
X 
X static volatile char irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1,
@@ -1091,12 +1100,14 @@
X 	int tmp;
X 	
X 	printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n");
-	printk("ad1816: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.28 1999/01/16 19:01:36 tek Exp $\n");
-	printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, isadmabug=%d\n",
+	printk("ad1816: $Header: /home/tek/CVSROOT/sound22/ad1816.c,v 1.3 1999/04/18 16:41:41 tek Exp $\n");
+	printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n",
X 	       hw_config->io_base,
X 	       hw_config->irq,
X 	       hw_config->dma,
X 	       hw_config->dma2,
+	       ad1816_clockfreq,
+	       options,
X 	       isa_dma_bridge_buggy);
X 
X 	if (check_region (io_base, 16)) {
@@ -1264,7 +1275,11 @@
X 	nr_ad1816_devs++;
X 
X 	ad_write(devc,32,0x80f0); /* sound system mode */
-	ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */
+	if (options&1) {
+	        ad_write(devc,33,0); /* disable all audiosources for dsp */
+	} else {
+	        ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */
+	}
X 	ad_write(devc,4,0x8080);  /* default values for volumes (muted)*/
X 	ad_write(devc,5,0x8080);
X 	ad_write(devc,6,0x8080);
@@ -1274,7 +1289,7 @@
X 	ad_write(devc,17,0x8888);
X 	ad_write(devc,18,0x8888);
X 	ad_write(devc,19,0xc888); /* +20db mic active */
-	ad_write(devc,14,0x0000); /* Master volume unmuted full power */
+	ad_write(devc,14,0x0000); /* Master volume unmuted */
X 	ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */
X 	ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */
X 	outb(0x10,devc->base+8); /* set dma mode */
@@ -1382,6 +1397,7 @@
X MODULE_PARM(dma,"i");
X MODULE_PARM(dma2,"i");
X MODULE_PARM(ad1816_clockfreq,"i");
+MODULE_PARM(options,"i");
X 
X struct address_info cfg;
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c
--- v2.2.7/linux/drivers/sound/sb_ess.c	Tue Feb 23 15:21:34 1999
+++ linux/drivers/sound/sb_ess.c	Mon May 10 13:01:21 1999
@@ -11,7 +11,7 @@
X  * History:
X  *
X  * Rolf Fokkens	(Dec 20 1998):	ES188x recording level support on a per
- *								input basis.
+ * fokk...@vertis.nl			input basis.
X  *				(Dec 24 1998):	Recognition of ES1788, ES1887, ES1888,
X  *								ES1868, ES1869 and ES1878. Could be used for
X  *								specific handling in the future. All except
@@ -32,6 +32,14 @@
X  *								any applications to test it though. So why did
X  *								I bother to create it anyway?? :) Just for
X  *								fun.
+ *				(May  2 1999):	I tried to be too smart by "introducing"
+ *								ess_calc_best_speed (). The idea was that two
+ *								dividers could be used to setup a samplerate,
+ *								ess_calc_best_speed () would choose the best.
+ *								This works for playback, but results in
+ *								recording problems for high samplerates. I
+ *								fixed this by removing ess_calc_best_speed ()
+ *								and just doing what the documentation says. 
X  *
X  * This files contains ESS chip specifics. It's based on the existing ESS
X  * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This
@@ -315,6 +323,7 @@
X 	return retval;
X }
X 
+#ifdef OBSOLETE
X static int ess_calc_best_speed
X 	(int clock1, int rev1, int clock2, int rev2, int *divp, int *speedp)
X {
@@ -338,6 +347,7 @@
X 
X 	return retval;
X }
+#endif
X 
X /*
X  * Depending on the audiochannel ESS devices can
@@ -349,7 +359,7 @@
X  */
X static void ess_common_speed (sb_devc *devc, int *speedp, int *divp)
X {
-	int diff = 0, div, choice;
+	int diff = 0, div;
X 
X 	if (devc->duplex) {
X 		/*
@@ -357,8 +367,11 @@
X 		 */
X 		div = 0x80 | ess_calc_div (795500, 128, speedp, &diff);
X 	} else {
-		choice = ess_calc_best_speed (397700, 128, 795500, 256, &div, speedp);
-		if (choice == 2) div |= 0x80;
+		if (*speedp > 22000) {
+			div = 0x80 | ess_calc_div (795500, 256, speedp, &diff);
+		} else {
+			div = 0x00 | ess_calc_div (397700, 128, speedp, &diff);
+		}
X 	}
X 	*divp = div;
X }
@@ -1144,6 +1157,18 @@
X 		if (chip == NULL) {
X 			chip = "ES1688";
X 		};
+
+	    printk ( KERN_INFO "ESS chip %s %s%s\n"
+               , chip
+               , ( esstype == ESSTYPE_DETECT || esstype == ESSTYPE_LIKE20
+                 ? "detected"
+                 : "specified"
+                 )
+               , ( esstype == ESSTYPE_LIKE20
+                 ? " (kernel 2.0 compatible)"
+                 : ""
+                 )
+               );
X 
X 		sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f);
X 	} else {
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- v2.2.7/linux/drivers/usb/CREDITS	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/CREDITS	Tue May 11 10:04:03 1999
@@ -2,14 +2,16 @@
X 
X The following people have contributed to this code (in alphabetical
X order by last name).  I'm sure this list should be longer, its
-difficult to maintain.
+difficult to maintain, add yourself with a patch if desired.
X 
+  Alan Cox <al...@lxorguk.ukuu.org.uk>
X   Johannes Erdfelt <jerd...@sventech.com>
X   ham <h...@unsuave.com>
X   Bradley M Keryan <ker...@andrew.cmu.edu>
X   Vojtech Pavlik <voj...@twilight.ucw.cz>
X   Gregory P. Smith <gr...@electricrain.com>
X   Linus Torvalds <torv...@transmeta.com>
+  Roman Weissgaerber <wei...@vienna.at>
X   <Kazuki.Y...@fujixerox.co.jp>
X 
X Special thanks to:
@@ -20,4 +22,133 @@
X 
X   The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
X   and offering suggestions and sharing implementation experiences.
+
+Additional thanks to the following companies and people for donations
+of hardware, support, time and development (this is from the original
+THANKS file in Inaky's driver):
+
+        The following corporations have helped us in the development
+of Linux USB / UUSBD:
+
+        - USAR Systems provided us with one of their excellent USB
+          Evaluation Kits. It allows us to test the Linux-USB driver
+          for compilance with the latest USB specification. USAR
+          Systems recognized the importance of an up-to-date open
+          Operating System and supports this project with
+          Hardware. Thanks!.
+
+        - Thanks to Intel Corporation for their precious help.
+
+        - We teamed up with Cherry to make Linux the first OS with
+          built-in USB support. Cherry is one of the biggest keyboard
+          makers in the world.
+
+        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
+          PCI-to-USB Controller Board to test the OHCI implementation.
+
+        - Due to their support to us, Keytronic can be sure that they
+          will sell keyboards to some of the 3 million (at least)
+          Linux users.
+
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+          It was almost imposible to get a PC backplate USB connector
+          for the motherboard here at Europe (mine, home-made, was
+          quite lowsy :). Now I know where to adquire nice USB stuff!
+
+        - Genius Germany donated a USB mouse to test the mouse boot
+          protocol. They've also donated a F-23 digital joystick and a
+          NetMouse Pro. Thanks! 
+
+        - AVM GmbH Berlin is supporting the development of the Linux
+          USB driver for the AVM ISDN Controller B1 USB. AVM is a
+          leading manufacturer for active and passive ISDN Controllers
+          and CAPI 2.0-based software. The active design of the AVM B1
+          is open for all OS platforms, including Linux.
+
+        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
+          USB Floppy Disk Drive, so we could test the bulk transfer
+          code.
+
+        - Many thanks to Logitech for contributing a three axis USB
+          mouse. 
+
+          Logitech designs, manufactures and markets
+          Human Interface Devices, having a long history and
+          experience in making devices such as keyboards, mice,
+          trackballs, cameras, loudspeakers and control devices for
+          gaming and professional use.
+
+          Being a recognized vendor and seller for all these devices,
+          they have donated USB mice, a joystick and a scanner, as a
+          way to acknowledge the importance of Linux and to allow
+          Logitech customers to enjoy support in their favorite
+          operating systems and all Linux users to use Logitech and
+          other USB hardware.
+
+          Logitech is official sponsor of the Linux Conference on
+          Feb. 11th 1999 in Vienna, where we'll will present the
+          current state of the Linux USB effort.
+
+        - CATC has provided means to uncover dark corners of the UHCI
+          inner workings with a USB Inspector.
+
+        - Thanks to Entrega for providing PCI to USB cards, hubs and
+          converter products for development. 
+
+
+        And thanks go to (hey! in no particular order :)
+
+        - Oren Tirosh <ore...@hishome.net>, for standing so patiently
+          all my doubts'bout USB and giving lots of cool ideas.
+
+        - Jochen Karrer <kar...@wpfd25.physik.uni-wuerzburg.de>, for
+          pointing out mortal bugs and giving advice.
+
+        - Edmund Humemberger <e...@atnet.at>, for it's great work on
+          public relationships and general management stuff for the
+          Linux-USB effort.
+
+        - Alberto Menegazzi <fl...@flash.iol.it> is starting the
+          documentation for the UUSBD. Go for it!
+
+        - Ric Klaren <ia_...@cs.utwente.nl> for doing nice
+          introductory documents (compiting with Alberto's :).
+
+        - Christian Groessler <c...@aladdin.de>, for it's help on those
+          itchy bits ... :)
+
+        - Paul MacKerras for polishing OHCI and pushing me harder for
+          the iMac support, giving improvements and enhancements.
+
+        - Fernando Herrera <fher...@eurielec.etsit.upm.es> has taken
+          charge of composing, maintaining and feeding the
+          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
+
+        - Rasca Gmelch <th...@gmx.de> has revived the raw driver and
+          pointed bugs, as well as started the uusbd-utils package.
+
+        - Peter Dettori <det...@ozy.dec.com> is unconvering bugs like
+          crazy, as well as making cool suggestions, great :)
+
+        - All the Free Software and Linux community, the FSF & the GNU
+          project, the MIT X consortium, the TeX people ... everyone!
+          You know who you are!
+
+        - Big thanks to Richard Stallman for creating Emacs!
+
+        - The people at the linux-usb mailing list, for reading so
+          many messages :) Ok, no more kidding; for all your advices!
+
+        - All the people at the USB Implementors Forum for their
+          help and assistance.
+
+        - Nathan Myers <n...@cantrip.org>, for his advice! (hope you
+          liked Cibeles' party).
+
+        - Linus Torvalds, for starting, developing and managing Linux.
+
+        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
+          for convincing me USB Standard hubs are not that standard
+          and that's good to allow for vendor specific quirks on the
+          standard hub driver.
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.2.7/linux/drivers/usb/Config.in	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/Config.in	Mon May 10 10:18:34 1999
@@ -16,6 +16,10 @@
X   if [ ! "$CONFIG_USB" = "n" ]; then
X     bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
X     bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
+    bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
+    if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
+       bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
+    fi
X 
X     bool 'USB mouse support' CONFIG_USB_MOUSE
X     bool 'USB keyboard support' CONFIG_USB_KBD
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.2.7/linux/drivers/usb/Makefile	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/Makefile	Mon May 10 10:18:34 1999
@@ -59,7 +59,17 @@
X   endif
X endif
X 
-
+ifeq ($(CONFIG_USB_OHCI_HCD),y)
+  ifeq ($(CONFIG_USB), y)
+    L_OBJS += ohci-hcd.o ohci-root-hub.o
+  else
+    ifeq ($(CONFIG_USB),m)
+      USBO_OBJS += ohci-hcd.o ohci-root-hub.o
+      M_OBJS += usb-ohci-hcd.o
+      MIX_OBJS += $(USBX_OBJS)
+    endif
+  endif
+endif
X include $(TOPDIR)/Rules.make
X 
X keymap.o: keymap.c
@@ -73,3 +83,6 @@
X usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS)
X 	$(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS)
X 
+usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
+       
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/README.ohci linux/drivers/usb/README.ohci
--- v2.2.7/linux/drivers/usb/README.ohci	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/README.ohci	Tue May 11 10:04:03 1999
@@ -1,8 +1,26 @@
-April 24, 1999 04:37:42 PST
+May 09, 1999 16:25:58
X 
-Okay, I've written a lot more of the OHCI code and actually got it back to
-a compiling state now with all of the recent improvements to the way stuff
-is structured.  It is completely untested.
+Cool, things are working "well" now.  (I'm not getting oops's from the
+OHCI code anyways.. ;).  I can attach a usb hub and mouse in any
+possible arrangement of the two and they get configured properly.
+
+You can see that the mouse Interrupt transfers are occuring and being
+acknowledged because /proc/interrupts usb-ohci goes up accordingly with
+mouse movements/events.  That means the TD at least returns some data
+and requeues itself.
+
+Device attach/detach from the root hub is not working well.  Currently
+every interrupt checks for root hub status changes and frame number
+overflow interrupts are enabled.  This means you shouldn't have to
+wait more than 32-33 seconds for the change to occur, less if there is
+other activity.  (due to checking in the WDH caused interrupts)
+My OHCI controller [SiS 5598 motherboard] doesn't seem to play well
+with the RHSC interrupt so it has been disabled.  The ohci_timer
+should be polling but it not currently working, I haven't had time to
+look into that problem.
+
+However, when I tried telling X to use /dev/psaux for the mouse my
+machine locked up...
X 
X - gr...@electricrain.com
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/README.ohci_hcd linux/drivers/usb/README.ohci_hcd
--- v2.2.7/linux/drivers/usb/README.ohci_hcd	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/README.ohci_hcd	Mon May 10 10:18:34 1999
@@ -0,0 +1,112 @@
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD  for the OHCI. 
+ (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
+
+- Roman Weissgaerber <wei...@vienna.at>
+
+
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04 
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ * 
+ * v0.1.0 1999/04/27 initial release
+ 
+to remove the module try:
+killall root-hub
+:
+rmmod usb-ohci-hcd
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete) 
+  this is an option now (v0.2.0)
+  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+  default is without. 
+  (at the moment: the Virtual Root Hub option is not recommended)
+  
+  files: ohci-root-hub.c, ohci-root-hub.h 
+ 
+
+- Endpoint Descriptor (ED) handling more static approach 
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is choosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ 
+ files: ohci-hcd.c ohci-hcd.h
+ routines:   (do not use for drivers, use the top layer alternate usb commands instead)
+ 
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
+            int interval, int load, f_handler handler, int ep_size, int speed)
+       adds an endpoint, (if the endpoint already exists some parameters will be updated)
+       
+ int usb_ohci_rm_ep(struct  usb_ohci_ed *ed, struct ohci * ohci) 
+       removes an endpoint and all pending TDs of that EP
+       
+  usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr)
+       removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+  to take care of buffer allocation.
+  files: ohci-hcd.c ohci-hcd.h 
+
+  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+  
+  int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+  
+  CTRL: ctrl, ctrl_len ... cmd buffer 
+        data, data_len ... data buffer (in or out)
+  INT, BULK:  ctrl = NULL, ctrl_len=0,
+  		data, data_len ... data buffer (in or out)
+  ISO: tbd
+
+  There is no buffer reinsertion done by the internal HCD function. 
+  (The interface layer does this for a INT-pipe on request.)
+  If you want a transfer then you have to 
+  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+  you can send as many as you like. They should come back by the callback f_handler in
+  the same order (for each endpoint, not globally) If an error occurs all
+  queued transfers of an endpoint will return unsent. They will be marked with an error status.
+  
+  e.g double-buffering for int transfers:
+
+   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  and when a data0 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  and when a data1 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+  The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does 
+  some error handling, root-hub request dequeuing
+  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+ep_addr union or int  is for addressing devices&endpoints: 
+__u8 ep_addr.bep.ep ... bit 3..0  endpoint address
+						bit 4     0
+						bit 6,5  type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO
+						bit 7	direction 1 IN, 0 OUT
+
+__u8 ep_addr.bep.fa ... bit 6..0  function address
+						bit 7	  0
+
+(__u8 ep_addr.bep.hc ... host controller nr) not used
+(__u8 ep_addr.bep.host ... host nr) not used
+
+
+  
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.2.7/linux/drivers/usb/hub.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/hub.c	Fri Apr 30 08:20:01 1999
@@ -30,6 +30,9 @@
X /* List of hubs needing servicing */
X static struct list_head hub_event_list;
X 
+/* PID of khubd */
+static int khubd_pid = 0;
+
X /*
X  * A irq handler returns non-zero to indicate to
X  * the low-level driver that it wants to be re-activated,
@@ -166,7 +169,8 @@
X 	/* Is it a hub? */
X 	if (interface->bInterfaceClass != 9)
X 		return -1;
-	if (interface->bInterfaceSubClass != 0)
+	if ((interface->bInterfaceSubClass != 0) &&
+	    (interface->bInterfaceSubClass != 1))
X 		return -1;
X 
X 	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
@@ -398,8 +402,10 @@
X 
X 	usb_register(&hub_driver);
X 	pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-	if (pid >= 0)
+	if (pid >= 0) {
+		khubd_pid = pid;
X 		return 0;
+	}
X 
X 	/* Fall through if kernel_thread failed */
X 	usb_deregister(&hub_driver);
@@ -407,3 +413,10 @@
X 	return 0;
X }
X 
+void hub_cleanup(void)
+{
+	if (khubd_pid >= 0)
+		kill_proc(khubd_pid, SIGINT, 1);
+
+	usb_deregister(&hub_driver);
+}
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.2.7/linux/drivers/usb/inits.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/inits.h	Fri Apr 30 08:20:30 1999
@@ -2,3 +2,5 @@
X int usb_kbd_init(void);
X int usb_audio_init(void);
X int hub_init(void);
+void hub_cleanup(void);
+void usb_mouse_cleanup(void);
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.2.7/linux/drivers/usb/mouse.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/mouse.c	Fri Apr 30 08:20:49 1999
@@ -1,9 +1,12 @@
X /*
X  * USB HID boot protocol mouse support based on MS BusMouse driver, psaux 
- * driver, and Linus's skeleton USB mouse driver
+ * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus.
X  *
X  * Brad Keryan 4/3/1999
X  *
+ * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
+ * correctly. Events are added together, not queued, to keep the rodent sober.
+ *
X  * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events.
X  * This is wrong: when an application (like X or gpm) reads the mouse device,
X  * it wants to find out the mouse's current position, not its recent history.
@@ -282,18 +285,9 @@
X 	return 0;
X }
X 
-#if 0
-
-int init_module(void)
-{
-	return usb_mouse_init();
-}
-
-void cleanup_module(void)
+void usb_mouse_cleanup(void)
X {
X 	/* this, too, probably needs work */
X 	usb_deregister(&mouse_driver);
X 	misc_deregister(&usb_mouse);
X }
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.2.7/linux/drivers/usb/ohci-debug.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/ohci-debug.c	Tue May 11 10:04:03 1999
@@ -14,40 +14,58 @@
X 	struct ohci_regs regs;
X 	int i;
X 
-	regs.revision = readl(ohci->regs->revision);
-	regs.control = readl(ohci->regs->control);
-	regs.cmdstatus = readl(ohci->regs->cmdstatus);
-	regs.intrstatus = readl(ohci->regs->intrstatus);
-	regs.intrenable = readl(ohci->regs->intrenable);
-	regs.intrdisable = readl(ohci->regs->intrdisable);
-	regs.hcca = readl(ohci->regs->hcca);
-	regs.ed_periodcurrent = readl(ohci->regs->ed_periodcurrent);
-	regs.ed_controlhead = readl(ohci->regs->ed_controlhead);
-	regs.ed_bulkhead = readl(ohci->regs->ed_bulkhead);
-	regs.ed_bulkcurrent = readl(ohci->regs->ed_bulkcurrent);
-	regs.current_donehead = readl(ohci->regs->current_donehead);
-	regs.fminterval = readl(ohci->regs->fminterval);
-	regs.fmremaining = readl(ohci->regs->fmremaining);
-	regs.fmnumber = readl(ohci->regs->fmnumber);
-	regs.periodicstart = readl(ohci->regs->periodicstart);
-	regs.lsthresh = readl(ohci->regs->lsthresh);
-	regs.roothub.a = readl(ohci->regs->roothub.a);
-	regs.roothub.b = readl(ohci->regs->roothub.b);
-	regs.roothub.status = readl(ohci->regs->roothub.status);
+	regs.revision = readl(&ohci->regs->revision);
+	regs.control = readl(&ohci->regs->control);
+	regs.cmdstatus = readl(&ohci->regs->cmdstatus);
+	regs.intrstatus = readl(&ohci->regs->intrstatus);
+	regs.intrenable = readl(&ohci->regs->intrenable);
+	regs.hcca = readl(&ohci->regs->hcca);
+	regs.ed_periodcurrent = readl(&ohci->regs->ed_periodcurrent);
+	regs.ed_controlhead = readl(&ohci->regs->ed_controlhead);
+	regs.ed_controlcurrent = readl(&ohci->regs->ed_controlcurrent);
+	regs.ed_bulkhead = readl(&ohci->regs->ed_bulkhead);
+	regs.ed_bulkcurrent = readl(&ohci->regs->ed_bulkcurrent);
+	regs.current_donehead = readl(&ohci->regs->current_donehead);
+	regs.fminterval = readl(&ohci->regs->fminterval);
+	regs.fmremaining = readl(&ohci->regs->fmremaining);
+	regs.fmnumber = readl(&ohci->regs->fmnumber);
+	regs.periodicstart = readl(&ohci->regs->periodicstart);
+	regs.lsthresh = readl(&ohci->regs->lsthresh);
+	regs.roothub.a = readl(&ohci->regs->roothub.a);
+	regs.roothub.b = readl(&ohci->regs->roothub.b);
+	regs.roothub.status = readl(&ohci->regs->roothub.status);
X 	for (i=0; i<MAX_ROOT_PORTS; ++i)
-		regs.roothub.portstatus[i] = readl(ohci->regs->roothub.portstatus[i]);
+		regs.roothub.portstatus[i] = readl(&ohci->regs->roothub.portstatus[i]);
X 
-	printk("  ohci revision    =  0x%x\n", regs.revision);
-	printk("  ohci control     =  0x%x\n", regs.control);
-	printk("  ohci cmdstatus   =  0x%x\n", regs.cmdstatus);
-	printk("  ohci intrstatus  =  0x%x\n", regs.intrstatus);
-	printk("  ohci roothub.a   =  0x%x\n", regs.roothub.a);
-	printk("  ohci roothub.b   =  0x%x\n", regs.roothub.b);
-	printk("  ohci root status =  0x%x\n", regs.roothub.status);
+	printk(KERN_DEBUG "  ohci revision    =  %x\n", regs.revision);
+	printk(KERN_DEBUG "  ohci control     =  %x\n", regs.control);
+	printk(KERN_DEBUG "  ohci cmdstatus   =  %x\n", regs.cmdstatus);
+	printk(KERN_DEBUG "  ohci intrstatus  =  %x\n", regs.intrstatus);
+	printk(KERN_DEBUG "  ohci intrenable  =  %x\n", regs.intrenable);
+
+	printk(KERN_DEBUG "  ohci hcca        =  %x\n", regs.hcca);
+	printk(KERN_DEBUG "  ohci ed_pdcur    =  %x\n", regs.ed_periodcurrent);
+	printk(KERN_DEBUG "  ohci ed_ctrlhead =  %x\n", regs.ed_controlhead);
+	printk(KERN_DEBUG "  ohci ed_ctrlcur  =  %x\n", regs.ed_controlcurrent);
+	printk(KERN_DEBUG "  ohci ed_bulkhead =  %x\n", regs.ed_bulkhead);
+	printk(KERN_DEBUG "  ohci ed_bulkcur  =  %x\n", regs.ed_bulkcurrent);
+	printk(KERN_DEBUG "  ohci curdonehead =  %x\n", regs.current_donehead);
+
+	printk(KERN_DEBUG "  ohci fminterval  =  %x\n", regs.fminterval);
+	printk(KERN_DEBUG "  ohci fmremaining =  %x\n", regs.fmremaining);
+	printk(KERN_DEBUG "  ohci fmnumber    =  %x\n", regs.fmnumber);
+	printk(KERN_DEBUG "  ohci pdstart     =  %x\n", regs.periodicstart);
+	printk(KERN_DEBUG "  ohci lsthresh    =  %x\n", regs.lsthresh);
+
+	printk(KERN_DEBUG "  ohci roothub.a   =  %x\n", regs.roothub.a);
+	printk(KERN_DEBUG "  ohci roothub.b   =  %x\n", regs.roothub.b);
+	printk(KERN_DEBUG "  ohci root status =  %x\n", regs.roothub.status);
+	printk(KERN_DEBUG "    roothub.port0  =  %x\n", regs.roothub.portstatus[0]);
+	printk(KERN_DEBUG "    roothub.port1  =  %x\n", regs.roothub.portstatus[1]);
X } /* show_ohci_status() */
X 
X 
-static void show_ohci_ed(struct ohci_ed *ed)
+void show_ohci_ed(struct ohci_ed *ed)
X {
X 	int stat = ed->status;
X 	int skip = (stat & OHCI_ED_SKIP);
@@ -57,82 +75,103 @@
X 	int dir = (stat & OHCI_ED_D);
X 	int endnum = (stat & OHCI_ED_EN) >> 7;
X 	int funcaddr = (stat & OHCI_ED_FA);
-	int halted = (ed->head_td & 1);
-	int toggle = (ed->head_td & 2) >> 1;
+	int halted = (ed->_head_td & 1);
+	int toggle = (ed->_head_td & 2) >> 1;
X 
-	printk("   ohci ED:\n");
-	printk("     status     =  0x%x\n", stat);
-	printk("       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
+	printk(KERN_DEBUG "   ohci ED:\n");
+	printk(KERN_DEBUG "     status     =  0x%x\n", stat);
+	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
X 			skip ? "Skip " : "",
X 			mps,
X 			isoc ? "Isoc. " : "",
-			low_speed ? "LowSpd " : "",
-			(dir == OHCI_ED_D_IN) ? "Input " :
-			(dir == OHCI_ED_D_OUT) ? "Output " : "",
-			halted ? "Halted " : "",
+			low_speed ? " LowSpd" : "",
+			(dir == OHCI_ED_D_IN) ? " Input" :
+			(dir == OHCI_ED_D_OUT) ? " Output" : "",
+			halted ? " Halted" : "",
X 			toggle,
X 			endnum,
X 			funcaddr);
-	printk("     tail_td    =  0x%x\n", ed->tail_td);
-	printk("     head_td    =  0x%x\n", ed->head_td);
-	printk("     next_ed    =  0x%x\n", ed->next_ed);
+	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed->tail_td);
+	printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
+	printk(KERN_DEBUG "     next_ed    =  0x%x\n", ed->next_ed);
X } /* show_ohci_ed() */
X 
X 
-static void show_ohci_td(struct ohci_td *td)
+void show_ohci_td(struct ohci_td *td)
X {
X 	int td_round = td->info & OHCI_TD_ROUND;
X 	int td_dir = td->info & OHCI_TD_D;
-	int td_int_delay = td->info & OHCI_TD_IOC_DELAY;
-	int td_toggle = td->info & OHCI_TD_DT;
-	int td_errcnt = td_errorcount(td->info);
-	int td_cc = td->info & OHCI_TD_CC;
-
-	printk("   ohci TD hardware fields:\n");
-	printk("      info     =  0x%x\n", td->info);
-	printk("        %s%s%s%d%s%s%d%s%d\n",
+	int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21;
+	int td_toggle = (td->info & OHCI_TD_DT) >> 24;
+	int td_errcnt = td_errorcount(*td);
+	int td_cc = OHCI_TD_CC_GET(td->info);
+
+	printk(KERN_DEBUG "   ohci TD hardware fields:\n");
+	printk(KERN_DEBUG "      info     =  0x%x\n", td->info);
+	printk(KERN_DEBUG "        %s%s%s%d %s\n",
X 		td_round ? "Rounding " : "",
X 		(td_dir == OHCI_TD_D_IN) ? "Input " :
X 		(td_dir == OHCI_TD_D_OUT) ? "Output " :
X 		(td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
-		"IntDelay ", td_int_delay >> 21,
-		td_toggle ? "Data1 " : "Data0 ",
+		"IntDelay ", td_int_delay,
+		(td_toggle < 2) ? " " :
+		(td_toggle & 1) ? "Data1 " : "Data0 ");
+	printk(KERN_DEBUG "        %s%d %s0x%x, %sAccessed, %sActive\n",
X 		"ErrorCnt ", td_errcnt,
-		"ComplCode ", td_cc);
-	printk("       %sAccessed, %sActive\n",
-			td_cc_accessed(td->info) ? "" : "Not ",
-			td_active(td->info) ? "" : "Not ");
-
-	printk("      cur_buf  =  0x%x\n", td->cur_buf);
-	printk("      next_td  =  0x%x\n", td->next_td);
-	printk("      buf_end  =  0x%x\n", td->buf_end);
-	printk("   ohci TD driver fields:\n");
-	printk("      data     =  %p\n", td->data);
-	printk("      dev_id   =  %p\n", td->dev_id);
-	printk("      ed_bus   =  %x\n", td->ed_bus);
+		"ComplCode ", td_cc,
+		td_cc_accessed(*td) ? "" : "Not ",
+		td_active(*td) ? "" : "Not ");
+
+	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", td->cur_buf);
+	printk(KERN_DEBUG "      next_td  =  0x%x\n", td->next_td);
+	printk(KERN_DEBUG "      buf_end  =  0x%x\n", td->buf_end);
+	printk(KERN_DEBUG "   ohci TD driver fields:\n");
+	printk(KERN_DEBUG "      data     =  %p\n", td->data);
+	printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
+	printk(KERN_DEBUG "      ed       =  %p\n", td->ed);
+	if (td->data != NULL) {
+	unsigned char *d = td->data;
+	printk(KERN_DEBUG "   DATA: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+			d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] );
+	}
X } /* show_ohci_td() */
X 
X 
X void show_ohci_device(struct ohci_device *dev)
X {
X 	int idx;
-	printk("  ohci_device usb       =  %p\n", dev->usb);
-	printk("  ohci_device ohci      =  %p\n", dev->ohci);
-	printk("  ohci_device ohci_hcca =  %p\n", dev->hcca);
-	for (idx=0; idx<8 /*NUM_EDS*/; ++idx) {
-		printk("   [ed num %d] ", idx);
+	printk(KERN_DEBUG "  ohci_device usb       =  %p\n", dev->usb);
+	printk(KERN_DEBUG "  ohci_device ohci      =  %p\n", dev->ohci);
+	printk(KERN_DEBUG "  ohci_device ohci_hcca =  %p\n", dev->hcca);
+	for (idx=0; idx<3 /*NUM_EDS*/; ++idx) {
+		printk(KERN_DEBUG "   [ed num %d] ", idx);
X 		show_ohci_ed(&dev->ed[idx]);
X 	}
-	for (idx=0; idx<8 /*NUM_TDS*/; ++idx) {
-		printk("   [td num %d] ", idx);
+	for (idx=0; idx<3 /*NUM_TDS*/; ++idx) {
+		printk(KERN_DEBUG "   [td num %d] ", idx);
X 		show_ohci_td(&dev->td[idx]);
X 	}
-	printk("  ohci_device data\n    ");
+	printk(KERN_DEBUG "  ohci_device data\n    ");
X 	for (idx=0; idx<4; ++idx) {
-		printk(" %08lx", dev->data[idx]);
+		printk(KERN_DEBUG " %08lx", dev->data[idx]);
X 	}
-	printk("\n");
+	printk(KERN_DEBUG "\n");
X } /* show_ohci_device() */
+
+
+void show_ohci_hcca(struct ohci_hcca *hcca)
+{
+	int idx;
+
+	printk(KERN_DEBUG "  ohci_hcca\n");
+
+	for (idx=0; idx<NUM_INTS; idx++) {
+		printk(KERN_DEBUG "    int_table[%2d]  == %p\n", idx, hcca->int_table +idx);
+	}
+
+	printk(KERN_DEBUG "    frame_no          == %d\n", hcca->frame_no);
+	printk(KERN_DEBUG "    donehead          == 0x%08x\n", hcca->donehead);
+} /* show_ohci_hcca() */
X 
X 
X /* vim:sw=8
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.2.7/linux/drivers/usb/ohci-hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-hcd.c	Tue May 11 09:55:45 1999
@@ -0,0 +1,1489 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <wei...@vienna.at>
+ *
+ * The OHCI HCD layer is a simple but nearly complete implementation of what the
+ * USB people would call a HCD  for the OHCI. 
+ * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * 
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ Open Host Controller Interface driver for USB. ]
+ * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
+ * [ (C) Copyright 1999 Gregory P. Smith <gr...@electricrain.com> ]
+ * [ $Log: ohci.c,v $ ]
+ * [ Revision 1.1  1999/04/05 08:32:30  greg ]
+ * 
+ * 
+ * v2.1 1999/05/09 ep_addr correction, code clean up
+ * v2.0 1999/05/04 
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c) (APM not tested; hub, usb_device, bus and related stuff)
+ * from Greg Smith (ohci.c) (reset controller handling, hub)
+ * 
+ * v1.0 1999/04/27 initial release
+ * ohci-hcd.c
+ */
+
+/* #define OHCI_DBG  */  /* printk some debug information */
+
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "usb.h"
+#include "ohci-hcd.h"
+#include "inits.h" 
+
+ 
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+ 
+
+static struct wait_queue *control_wakeup;         
+static struct wait_queue *root_hub = NULL;
+ 
+static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */
+/* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */
+/* No  Error  */		0x00,
+/* CRC Error  */		0x04,
+/* Bit Stuff  */		0x02,
+/* Data Togg  */ 		0x40,
+/* Stall      */		0x40,
+/* DevNotResp */		0x04,
+/* PIDCheck   */		0x04,
+/* UnExpPID   */		0x40,
+/* DataOver   */		0x20,
+/* DataUnder  */ 		0x20,
+/* reservd    */		0x40,
+/* reservd    */		0x40,
+/* BufferOver */		0x20,
+/* BuffUnder  */		0x20,
+/* Not Access */		0x80,
+/* Not Access */		0x80
+ };
+ 
+ 
+/********
+ **** Interface functions
+ ***********************************************/
+ 
+static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
+{
+
+	struct ohci * ohci = ohci_in; 
+	usb_device_irq handler=(void *) lw0;
+	void *dev_id = (void *) lw1;
+	int ret;
+	
+	OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: %x: data(%d):", ep_addr, data_len);)
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+	
+ 	ret = handler(cc_to_status[status & 0xf], data, dev_id);
+	if(ret == 0) return 0; /* 0 .. do not requeue  */
+	if(status > 0) return -1; /* error occured do not requeue ? */
+	ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */
+	return 0;
+}
+
+static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw)
+{  
+	*(int * )lw0 = status;
+	wake_up(&control_wakeup);
+
+	OHCI_DEBUG( { int i; printk("USB HC CTRL<<<: %x: ctrl(%d):", ep_addr, ctrl_len);)
+	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) ctrl)[i]);)
+	OHCI_DEBUG( printk(" data(%d):", data_len);) 
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+    return 0;                       
+} 
+                                                             
+static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	union ep_addr_ ep_addr;
+	
+	ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */
+				| (pipe  & 0x80)  	 			/* direction */
+				| (1 << 5);						/* type = int*/
+	ep_addr.bep.fa = ((pipe >> 8) & 0x7f);			/* device address */
+
+	OHCI_DEBUG( printk("USB HC IRQ >>>: %x: every %d ms\n", ep_addr.iep, period);) 
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, period, 1, sohci_int_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+   	ohci_trans_req(ohci, ep_addr.iep, 0, NULL, ((struct ohci_device *) usb_dev->hcpriv)->data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id);
+	return 0;
+}
+
+
+static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+{
+	struct wait_queue wait = { current, NULL }; 
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	int status;
+	union ep_addr_ ep_addr;
+
+    ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */		
+				| (pipe  & 0x80)  				/* direction */
+				|  (1 << 6);					/* type = ctrl*/
+	ep_addr.bep.fa	= ((pipe >> 8) & 0x7f);				/* device address */
+	
+	status = 0xf; /* CC not Accessed */
+	OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ep_addr.iep, 8);)
+	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);)
+	OHCI_DEBUG( printk(" data(%d):", len);) 
+	OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk("\n"); })
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_ctrl_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+	current->state = TASK_UNINTERRUPTIBLE;
+    add_wait_queue(&control_wakeup, &wait);   
+ 
+	ohci_trans_req(ohci, ep_addr.iep, 8, cmd, data, len, (__OHCI_BAG) &status, 0);
+
+	schedule_timeout(HZ/10);
+
+    remove_wait_queue(&control_wakeup, &wait); 
+     
+    OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);)
+     
+	return cc_to_status[status & 0x0f];
+}
+
+
+static int sohci_usb_deallocate(struct usb_device *usb_dev) {
+    struct ohci_device *dev = usb_to_ohci(usb_dev); 
+	union ep_addr_ ep_addr;
+
+	ep_addr.iep = 0;
+	
+	OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);)
+
+	/* wait_ms(20); */
+
+	if(usb_dev->devnum >=0) {
+		ep_addr.bep.fa = usb_dev->devnum;
+    	usb_ohci_rm_function(((struct ohci_device *)usb_dev->hcpriv)->ohci, ep_addr.iep);
+	}
+	
+    USB_FREE(dev);
+	USB_FREE(usb_dev);
+
+	return 0;
+}
+
+static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
+ 
+	struct usb_device *usb_dev;
+	struct ohci_device *dev;
+	
+	
+	USB_ALLOC(usb_dev, sizeof(*usb_dev));
+	if (!usb_dev)
+		return NULL;
+		
+	memset(usb_dev, 0, sizeof(*usb_dev));
+
+	USB_ALLOC(dev, sizeof(*dev));
+	if (!dev) {
+		USB_FREE(usb_dev);
+		return NULL;
+	}
+
+	/* Initialize "dev" */
+	memset(dev, 0, sizeof(*dev));
+
+	usb_dev->hcpriv = dev;
+	dev->usb = usb_dev;
+
+	usb_dev->parent = parent;
+
+	if (parent) {
+		usb_dev->bus = parent->bus;
+		dev->ohci = usb_to_ohci(parent)->ohci;
+	}
+	return usb_dev;
+}
+
+struct usb_operations sohci_device_operations = {
+	sohci_usb_allocate,
+	sohci_usb_deallocate,
+	sohci_control_msg,
+	sohci_request_irq,
+};
+
+ 
+/******
+ *** ED handling functions
+ ************************************/
+
+
+
+/* 
+ * search for the right place to insert an interrupt ed into the int tree 
+ * do some load ballancing
+ * */
+
+static int usb_ohci_int_ballance(struct ohci * ohci, int interval, int load) {
+
+  int i,j;
+  
+  j = 0;   /* search for the least loaded interrupt endpoint branch of all 32 branches */
+  for(i=0; i< 32; i++) if(ohci->ohci_int_load[j] > ohci->ohci_int_load[i]) j=i; 
+
+  if(interval < 1) interval = 1;
+  if(interval > 32) interval = 32;
+  for(i= 0; ((interval >> i) > 1 ); interval &= (0xfffe << i++ )); /* interval = 2^int(ld(interval)) */
+  
+
+  for(i=j%interval; i< 32; i+=interval) ohci->ohci_int_load[i] += load;
+  j = interval + (j % interval); 
+  
+  OHCI_DEBUG(printk("USB HC new int ed on pos : %x \n",j);)
+  
+  return j;
+}
+
+/* get the ed from the endpoint / device adress */
+
+struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in) {
+
+union ep_addr_ ep_addr;
+struct usb_ohci_ed *tmp;
+unsigned int mask;
+
+mask = 0;
+ep_addr.iep = ep_addr_in;
+
+#ifdef VROOTHUB
+ if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
+ 	if((ep_addr.bep.ep & 0x0f) == 0)
+ 		return &ohci->ed_rh_ep0; /* root hub ep0 */
+ 	else
+ 		return &ohci->ed_rh_epi; /* root hub int ep */
+ }
+#endif
+
+ tmp = ohci->ed_func_ep0[ep_addr.bep.fa];
+ mask = ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); 
+ ep_addr.bep.ep &= mask; /* mask out direction of ctrl ep */
+ 
+  while (tmp != NULL) {
+    if (tmp->ep_addr.iep == ep_addr.iep) 
+      return tmp;
+    tmp = tmp->ed_list;
+  }
+  return NULL;
+}
+ 
+spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+/* add a new endpoint ep_addr */
+struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr_in, int interval, int load, f_handler handler, int ep_size, int speed) {
+   
+  struct usb_ohci_ed * ed; 
+  struct usb_ohci_td * td;
+  union ep_addr_ ep_addr;
+ 
+   
+  int int_junk;
+ 
+  struct usb_ohci_ed *tmp;
+
+  ep_addr.iep = ep_addr_in ;
+  ep_addr.bep.ep &= ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); /* mask out direction of ctrl ep */
+
+  spin_lock(&usb_ed_lock);
+  
+  tmp =  ohci_find_ep(ohci, ep_addr.iep);
+  if (tmp != NULL) { 
+  
+#ifdef VROOTHUB
+  	if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
+ 		if((ep_addr.bep.ep & 0x0f) != 0) { /* root hub int ep */
+			ohci->ed_rh_epi.handler = handler;
+ 			ohci_init_rh_int_timer(ohci, interval);
+ 		}
+ 		else { /* root hub ep0 */
+ 			 ohci->ed_rh_ep0.handler = handler;
+ 		}			 	
+ 	}
+
+ 	else 
+#endif 
+
+ 		{
+ 		tmp->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
+  		
+    	| (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
+    	| (speed << 13)
+    	| ep_size <<16;
+ 
+  		tmp->handler = handler; 
+  	}
+ 	spin_unlock(&usb_ed_lock);
+    return tmp;    /* ed  already in use */
+  }
+  
+  
+  OHCI_ALLOC(td, sizeof(td)); /* dummy td; end of td list for ed */
+  OHCI_ALLOC(ed, sizeof(ed));
+  td->prev_td = NULL;
+  
+  ed->hw.tail_td = virt_to_bus(&td->hw);
+  ed->hw.head_td = ed->hw.tail_td;
+  ed->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
+  /*  | ((ep_addr.bep.port & 0x80)? 0x1000 : 0x0800 ) */
+    | (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
+    | (speed << 13)
+    | ep_size <<16;
+  
+  ed->handler = handler;
+
+  switch((ep_addr.bep.ep >> 5) & 0x03) {
+  case CTRL:
+    ed->hw.next_ed = 0;
+    if(ohci->ed_controltail == NULL) {
+      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_controlhead);
+    }
+    else {
+      ohci->ed_controltail->hw.next_ed = virt_to_bus(&ed->hw);
+    }
+    ed->ed_prev = ohci->ed_controltail;
+    ohci->ed_controltail = ed;	  
+    break;
+  case BULK:  
+    ed->hw.next_ed = 0;
+    if(ohci->ed_bulktail == NULL) {
+      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_bulkhead);
+    }
+    else {
+      ohci->ed_bulktail->hw.next_ed = virt_to_bus(&ed->hw);
+    }
+    ed->ed_prev = ohci->ed_bulktail;
+    ohci->ed_bulktail = ed;	  
+    break;
+  case INT:
+    int_junk = usb_ohci_int_ballance(ohci, interval, load);
+    ed->hw.next_ed = ohci->hc_area->ed[int_junk].next_ed; 
+    ohci->hc_area->ed[int_junk].next_ed = virt_to_bus(&ed->hw);
+    ed->ed_prev = (struct usb_ohci_ed *) &ohci->hc_area->ed[int_junk];
+    break;
+  case ISO:
+    ed->hw.next_ed = 0;
+    ohci->ed_isotail->hw.next_ed = virt_to_bus(&ed->hw);
+    ed->ed_prev = ohci->ed_isotail;
+    ohci->ed_isotail = ed;	  
+    break;
+  }
+  ed->ep_addr  = ep_addr;
+  
+  /* Add it to the "hash"-table of known endpoint descriptors */      
+  
+  ed->ed_list = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
+  ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed; 
+
+  spin_unlock(&usb_ed_lock);
+  
+  OHCI_DEBUG(printk("USB HC new ed %x: %x :", ep_addr.iep, (unsigned int ) ed); )
+  OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
+  return 0;
+}
+
+/*****
+ * Request the removal of an endpoint
+ * 
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start of frame hardware interrupt 
+ */
+int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed)
+{    
+  unsigned int flags;
+  struct usb_ohci_ed *tmp;
+  
+  OHCI_DEBUG(printk("USB HC remove ed %x: %x :\n", ed->ep_addr.iep, (unsigned int ) ed); )
+
+  spin_lock_irqsave(&usb_ed_lock, flags);
+
+  tmp = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
+  if (tmp == NULL) {
+  	spin_unlock_irqrestore(&usb_ed_lock, flags);
+    return 0;
+  }
+
+  if(tmp == ed) {
+     ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed->ed_list;
+  }
+  else {
+    while (tmp->ed_list != ed) {
+      if (tmp->ed_list == NULL) {
+        spin_unlock_irqrestore(&usb_ed_lock, flags);
+		return 0;
+	  }
+      tmp = tmp->ed_list;
+    }
+    tmp->ed_list = ed->ed_list;
+  }
+  ed->ed_list = ohci->ed_rm_list;
+  ohci->ed_rm_list = ed;
+  ed->hw.info  |=  OHCI_ED_SKIP;
+
+  switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
+  	case CTRL:
+    	writel_mask(~(0x01<<4), &ohci->regs->control); /* stop CTRL list */
+    	break;
+  	case BULK:
+    	writel_mask(~(0x01<<5), &ohci->regs->control); /* stop BULK list */
+    	break;
+  }
+
+
+  writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
+
+  spin_unlock_irqrestore(&usb_ed_lock, flags);
+
+  return 1;
+}
+
+/* we have requested to stop the bulk or CTRL list,
+ * now we can remove the eds on the rm_list */
+ 
+static int ohci_rm_eds(struct ohci * ohci) {
+
+  unsigned int flags;
+  struct usb_ohci_ed *ed;
+  struct usb_ohci_ed *ed_tmp;
+  struct usb_ohci_td *td;
+  __u32 td_hw_tmp;
+  __u32 td_hw;
+  
+  spin_lock_irqsave(&usb_ed_lock, flags);
+
+  ed = ohci->ed_rm_list;
+
+  while (ed != NULL) {
+    
+    switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
+    case CTRL: 
+      if(ed->ed_prev == NULL) {
+		writel(ed->hw.next_ed, &ohci->regs->ed_controlhead);
+      }
+      else {
+		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      }
+      if(ohci->ed_controltail == ed) {
+		ohci->ed_controltail = ed->ed_prev;
+      }
+      break;
+    case BULK: 
+      if(ed->ed_prev == NULL) {
+		writel(ed->hw.next_ed, &ohci->regs->ed_bulkhead);
+      }
+      else {
+		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      }
+      if(ohci->ed_bulktail == ed) {
+		ohci->ed_bulktail = ed->ed_prev;
+      }
+      break;
+    case INT: 
+      	ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      break;
+    case ISO:
+      ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      if(ohci->ed_isotail == ed) {
+		ohci->ed_isotail = ed->ed_prev;
+      }
+      break;
+    }
+    
+    if(ed->hw.next_ed != 0) ((struct usb_ohci_ed *) bus_to_virt(ed->hw.next_ed))->ed_prev = ed->ed_prev;
+    
+
+/* tds directly connected to ed */
+ 
+	td_hw = ed->hw.head_td & 0xfffffff0;
+    while(td_hw != 0) {
+    	td = bus_to_virt(td_hw);
+    	td_hw_tmp = td_hw;
+    	td_hw = td->hw.next_td;
+    	OHCI_FREE(td); /* free pending tds */ 
+    	if(td_hw_tmp == ed->hw.tail_td) break;
+    	
+    }
+     
+    /* mark TDs on the hc done list (if there are any) */      
+	td_hw = readl(&ohci->regs->donehead) & 0xfffffff0;
+    while(td_hw != 0) {
+    	td = bus_to_virt(td_hw);
+    	td_hw = td->hw.next_td;
+    	if(td->ep == ed) td->ep = 0;
+   	}
+ 
+    /* mark TDs on the hcca done list (if there are any) */      
+	td_hw = ohci->hc_area->hcca.done_head & 0xfffffff0 ;
+	
+    while(td_hw != 0) { 
+    	td = bus_to_virt(td_hw); 
+    	td_hw = td->hw.next_td;
+    	if(td->ep == ed) td->ep = 0;
+   	}
+
+    ed_tmp = ed;
+    ed = ed->ed_list;
+    OHCI_FREE(ed_tmp);  /* free ed */ 
+  }
+  writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
+  writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
+  writel_set((0x01<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
+
+  spin_unlock_irqrestore(&usb_ed_lock, flags);
+  
+  ohci->ed_rm_list = NULL;
+  OHCI_DEBUG(printk("USB HC after rm ed control: %4x  intrstat: %4x intrenable: %4x\n", readl(&ohci->regs->control),readl(&ohci->regs->intrstatus),readl(&ohci->regs->intrenable));)
+ 
+
+  return 0;
+}
+
+/* remove all endpoints of a function (device) */
+int usb_ohci_rm_function( struct ohci * ohci, unsigned int ep_addr_in)
+{    
+  struct usb_ohci_ed *ed;
+  struct usb_ohci_ed *tmp;
+  union ep_addr_ ep_addr;
+
+ 
+  
+  ep_addr.iep = ep_addr_in;
+
+  for(ed = ohci->ed_func_ep0[ep_addr.bep.fa]; ed != NULL;) {
+	tmp = ed;
+    ed = ed->ed_list;
+    usb_ohci_rm_ep(ohci, tmp);
+  }
+ 
+
+  
+  return 1;
+}
+
+
+
+
+
+/******
+ *** TD handling functions
+ ************************************/
+
+
+#define FILL_TD(TD_PT, HANDLER, INFO, DATA, LEN, LW0, LW1)  \
+    td_pt = (TD_PT); \
+    td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); \
+    td_pt1->ep = usb_ep; \
+    td_pt1->handler = (HANDLER); \
+    td_pt1->buffer_start = (DATA); \
+    td_pt1->lw0 = (LW0); \
+    td_pt1->lw1 = (LW1); \
+    td_pt1->hw.info = (INFO); \
+    td_pt1->hw.cur_buf = virt_to_bus(DATA); \
+    td_pt1->hw.buf_end = td_pt1->hw.cur_buf + (LEN) - 1; \
+    td_pt1->hw.next_td = virt_to_bus(td_pt); \
+    usb_ep->hw.tail_td = virt_to_bus(td_pt); \
+    td_pt->prev_td = td_pt1; \
+    td_pt->hw.next_td = 0
+
+spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED;
+
+int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) {
+
+  int ed_type;
+  unsigned int flags;
+  struct usb_ohci_td *td_pt;
+  struct usb_ohci_td *td_pt1;
+  struct usb_ohci_td *td_pt_a1, *td_pt_a2, *td_pt_a3;
+  struct usb_ohci_ed *usb_ep;
+  f_handler handler;
+
+  
+ td_pt_a1 =NULL;
+ td_pt_a2 =NULL;
+ td_pt_a3 =NULL;
+  
+  usb_ep = ohci_find_ep(ohci, ep_addr);
+  if(usb_ep == NULL ) return -1; /* not known ep */
+  
+  handler = usb_ep->handler;
+ 
+#ifdef VROOTHUB 
+  if(usb_ep == &ohci->ed_rh_ep0) { /* root hub ep 0 control endpoint */  
+    root_hub_control_msg(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);
+    return 0;
+  }
+
+  if(usb_ep == &ohci->ed_rh_epi) { /* root hub interrupt endpoint */
+  
+    root_hub_int_req(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);  
+	return 0;
+  }
+#endif
+  /*  struct usb_ohci_ed * usb_ep = usb_ohci_add_ep(pipe, ohci, interval, 1); */
+ 
+   ed_type = ((((union ep_addr_)ep_addr).bep.ep >> 5) & 0x07);
+  
+  switch(ed_type) {
+  case BULK_IN:
+  case BULK_OUT:   
+  case INT_IN:
+  case INT_OUT:    
+    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
+    break;
+
+  case CTRL_IN:
+  case CTRL_OUT:
+    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
+    OHCI_ALLOC(td_pt_a3, sizeof(td_pt_a3));  
+    if(data_len > 0) {
+      OHCI_ALLOC(td_pt_a2, sizeof(td_pt_a2));
+    }
+    break;
+
+  case ISO_IN:
+  case ISO_OUT:
+
+  }
+    
+  spin_lock_irqsave(&usb_req_lock, flags);
+  
+  switch(ed_type) {
+  case BULK_IN:
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 22'
echo 'File patch-2.2.8 is continued in part 23'
echo 23 > _shar_seq_.tmp
#!/bin/sh
# this is part 23 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 23; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+    break;
+
+  case BULK_OUT: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+    break;
+
+  case INT_IN: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );  
+    break;
+
+  case INT_OUT: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    break;
+
+  case CTRL_IN: 
+    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
+    if(data_len > 0) { 
+      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R |  TD_DP_IN | TD_T_DATA1, data, data_len, 0, 0 );  
+    } 
+    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_OUT | TD_T_DATA1, NULL, 0, lw0, lw1 );
+    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+    break;
+
+  case CTRL_OUT:     
+    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
+    if(data_len > 0) { 
+      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1, data, data_len, 0, 0 );  
+    } 
+    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_IN | TD_T_DATA1, NULL, 0, lw0, lw1 );
+    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+    break;
+
+  case ISO_IN:
+  case ISO_OUT:
+    break;
+  }
+
+
+  
+
+ td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); 
+
+ 
+  if(td_pt_a3 != NULL) td_pt_a3->prev_td = NULL;
+  	else if (td_pt_a2 != NULL) td_pt_a2->prev_td = NULL;
+  	  	else if (td_pt_a1 != NULL) td_pt_a1->prev_td = NULL;
+  	  
+  spin_unlock_irqrestore(&usb_req_lock, flags);
+  return 0;
+}
+
+
+/******
+ *** Done List handling functions
+ ************************************/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+ 
+static struct usb_ohci_td * ohci_reverse_done_list(struct ohci * ohci) {
+
+  __u32 td_list_hc;
+  struct usb_ohci_td      * td_list = NULL;
+  struct usb_ohci_td      * td_rev = NULL;
+  	
+	td_list_hc = ohci->hc_area->hcca.done_head & 0xfffffff0;
+    ohci->hc_area->hcca.done_head = 0;
+    
+ 	while(td_list_hc) {
+		
+		td_list = (struct  usb_ohci_td *) bus_to_virt(td_list_hc);
+		td_list->next_dl_td = td_rev;
+			
+		td_rev = td_list;
+		td_list_hc = td_list->hw.next_td & 0xfffffff0;
+	}
+ return td_list;
+}
+
+/* all done requests are replied here */
+static int usb_ohci_done_list(struct ohci *  ohci) {
+
+  struct usb_ohci_td      * td = NULL;
+  struct usb_ohci_td      * td_list; 
+  struct usb_ohci_td      * td_list_next = NULL;
+  struct usb_ohci_td      * td_err = NULL;
+	__u32 td_hw;
+ 
+	
+  td_list = ohci_reverse_done_list(ohci);
+
+  while(td_list) {
+   	td_list_next = td_list->next_dl_td;
+    td = td_list;
+
+    if(td->ep == NULL) { /* removed ep */
+   		OHCI_FREE(td_list);
+   		break;
+   	}
+   	
+   	/* the HC halts an ED if an error occurs; put all pendings TDs of an halted ED on the
+   	 * done list; they are marked with an 0xf CC_error code 
+   	 */
+   	 
+ 	if(TD_CC_GET(td_list->hw.info) != TD_CC_NOERROR) { /* on error move all pending tds of an ed into the done list */
+ 		printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hw.info), td_list->ep->ep_addr.iep);
+    td_err= td_list;
+	td_hw = td_list->ep->hw.head_td & 0xfffffff0;
+    while(td_hw != 0) { 
+    	if(td_hw == td_list->ep->hw.tail_td) break;
+    	td = bus_to_virt(td_hw);
+    	td_err->next_dl_td = td;
+    	td_err= td;
+    	td_hw = td->hw.next_td;
+    }
+    td_list->ep->hw.head_td = td_list->ep->hw.tail_td;
+    td->next_dl_td = td_list_next;
+    td_list_next = td_list->next_dl_td;
+ 	
+    }
+  /*  send the reply  */
+ 	if(td_list->handler != NULL)  {
+    	if(td_list->prev_td == NULL) {
+			td_list->handler((void *) ohci,
+						td_list->ep->ep_addr.iep,
+						0, 
+						NULL, 
+						td_list->buffer_start, 
+						td_list->hw.buf_end-virt_to_bus(td_list->buffer_start)+1, 
+						TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1);
+			OHCI_FREE(td_list);			
+   	  	}
+      	else {
+      		if(td_list->prev_td->prev_td == NULL) { /* cntrl 2 Transactions dataless */
+	  		td_list->handler((void *) ohci,
+	  		            td_list->ep->ep_addr.iep,
+	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1,
+	  					td_list->prev_td->buffer_start, 
+	  					NULL,
+	  					0, 
+	  					(TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1);
+			OHCI_FREE(td_list->prev_td);
+			OHCI_FREE(td_list);
+			}
+			else { /* cntrl 3 Transactions */
+	  			td_list->handler((void *) ohci,
+	  					td_list->ep->ep_addr.iep, 
+	  					td_list->prev_td->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->prev_td->buffer_start)+1, 
+	  					td_list->prev_td->prev_td->buffer_start, 
+	  					td_list->prev_td->buffer_start, 
+	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1, 
+	  					(TD_CC_GET(td_list->prev_td->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->prev_td->hw.info)
+	  						: (TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1); 
+				OHCI_FREE(td_list->prev_td->prev_td);			
+				OHCI_FREE(td_list->prev_td);
+				OHCI_FREE(td_list);
+					
+			}
+      	} 
+    	
+    }
+ td_list = td_list_next;
+  }  
+  return 0; 
+}
+
+
+
+/******
+ *** HC functions
+ ************************************/
+ 
+
+ 
+void reset_hc(struct ohci *ohci) {
+	int retries = 5;
+	int timeout = 30;
+	int fminterval;
+	
+	if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */
+		writel(0x08,  &ohci->regs->cmdstatus); /* request ownership */
+		printk("USB HC TakeOver from SMM\n");
+		do {
+			wait_ms(100);
+			if(--retries) { 
+				printk("USB HC TakeOver timed out!\n");
+				break;
+			}
+		}
+		while(readl(&ohci->regs->control) & 0x100); 
+	}	
+		
+	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+	OHCI_DEBUG(printk("USB HC reset_hc: %x ; retries: %d\n", readl(&ohci->regs->control), 5-retries);)
+	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
+	while ((readl(&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+		if (--timeout == 0) {
+			printk("USB HC reset timed out!\n");
+			return;
+		}	
+		udelay(1);
+	}
+	/* set the timing */
+	fminterval |= (((fminterval -210) * 6)/7)<<16; 
+	writel(fminterval, &ohci->regs->fminterval);
+	writel(((fminterval&0x3fff)*9)/10, &ohci->regs->periodicstart);
+}
+
+
+/*
+ * Reset and start an OHCI controller
+ */
+void start_hc(struct ohci *ohci)
+{
+   /*  int fminterval; */
+    unsigned int mask;
+  /*  fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+	reset_hc(ohci); */
+ 
+
+	writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */
+ 
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_MIE | OHCI_INTR_WDH;
+	/* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF|  
+		OHCI_INTR_FNO */
+		
+
+	 
+	writel((0x00), &ohci->regs->control); /* USB Reset BUS */
+	wait_ms(10);
+	  
+	writel((0x97), &ohci->regs->control); /* USB Operational  */
+	
+ 	writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
+	wait_ms(50); 
+		
+	OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); )
+ 	OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstatu: %x \n", readl( &(ohci->regs->roothub.status) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) )); )
+   	OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) )); )
+  
+	/* control_wakeup = NULL; */
+	writel(mask, &ohci->regs->intrenable);
+	writel(mask, &ohci->regs->intrstatus);
+ 
+#ifdef VROOTHUB
+	{
+
+	struct usb_device * usb_dev;
+	struct ohci_device *dev;
+
+	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv; 
+
+	dev->ohci = ohci; 
+
+	usb_connect(usb_dev);
+
+	ohci->root_hub->usb->children[0] = usb_dev;
+
+	usb_new_device(usb_dev);
+	}
+#endif
+
+ 
+	
+}
+
+
+
+
+static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
+{
+  struct ohci *ohci = __ohci;
+  struct ohci_regs *regs = ohci->regs;
+ 
+  int ints; 
+
+ 
+ if((ohci->hc_area->hcca.done_head != 0) && !(ohci->hc_area->hcca.done_head & 0x01)) {
+    ints =  OHCI_INTR_WDH;
+  }
+  else { 
+    if((ints = (readl(®s->intrstatus) & readl(®s->intrenable))) == 0)
+      return;
+   } 
+   
+  ohci->intrstatus |= ints;
+  OHCI_DEBUG(printk("USB HC interrupt: %x (%x) \n", ints, readl(&ohci->regs->intrstatus));)
+
+  /* ints &= ~(OHCI_INTR_WDH);  WH Bit will be set by done list subroutine */
+ /*  if(ints & OHCI_INTR_FNO) {
+   	writel(OHCI_INTR_FNO,  ®s->intrstatus);
+   	if (waitqueue_active(&ohci_tasks)) wake_up(&ohci_tasks);
+  } */
+  
+  if(ints & OHCI_INTR_WDH) {
+   	writel(OHCI_INTR_WDH,  ®s->intrdisable);	
+   	ohci->intrstatus &= (~OHCI_INTR_WDH);
+	usb_ohci_done_list(ohci); /* prepare out channel list */
+	writel(OHCI_INTR_WDH, &ohci->regs->intrstatus);
+	writel(OHCI_INTR_WDH, &ohci->regs->intrenable);
+   	 
+  }
+  
+  if(ints & OHCI_INTR_SF) {
+  	writel(OHCI_INTR_SF,  ®s->intrdisable);	
+  	writel(OHCI_INTR_SF, &ohci->regs->intrstatus);
+	ohci->intrstatus &= (~OHCI_INTR_SF);
+  	if(ohci->ed_rm_list != NULL) {
+			ohci_rm_eds(ohci);
+ 	 }
+  }
+#ifndef VROOTHUB 
+  if(ints & OHCI_INTR_RHSC) {  
+  	writel(OHCI_INTR_RHSC, ®s->intrdisable);
+  	writel(OHCI_INTR_RHSC, &ohci->regs->intrstatus);
+	wake_up(&root_hub);
+
+  }
+ #endif
+
+  writel(OHCI_INTR_MIE, ®s->intrenable);
+	
+}
+ 
+#ifndef VROOTHUB
+/*
+ * This gets called if the connect status on the root
+ * hub (and the root hub only) changes.
+ */
+static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
+{
+	struct usb_device *usb_dev;
+    struct ohci_device *dev;
+	OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );)
+
+	/*
+	 * Even if the status says we're connected,
+	 * the fact that the status bits changed may
+	 * that we got disconnected and then reconnected.
+	 *
+	 * So start off by getting rid of any old devices..
+	 */
+	usb_disconnect(&ohci->root_hub->usb->children[port_nr]);
+
+	 if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) {
+	 	writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]);
+		return; /* nothing connected */
+	}
+	/*
+	 * Ok, we got a new connection. Allocate a device to it,
+	 * and find out what it wants to do..
+	 */
+	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv; 
+	dev->ohci = ohci; 
+	usb_connect(dev->usb);
+	ohci->root_hub->usb->children[port_nr] = usb_dev;
+	wait_ms(200); /* wait for powerup */
+    /* reset port/device */
+ 	writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */
+ 	while(!(readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_PRSC)) wait_ms(10); /* reset active ? */
+ 	writel(RH_PS_PES, &ohci->regs->roothub.portstatus[port_nr]); /* enable port */
+ 	wait_ms(10);
+	/* Get speed information */
+	usb_dev->slow = (readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_LSDA) ? 1 : 0;
+
+	/*
+	 * Ok, all the stuff specific to the root hub has been done.
+	 * The rest is generic for any new USB attach, regardless of
+	 * hub type.
+	 */
+	usb_new_device(usb_dev);
+}
+#endif
+ 
+
+
+/*
+ * Allocate the resources required for running an OHCI controller.
+ * Host controller interrupts must not be running while calling this
+ * function.
+ *
+ * The mem_base parameter must be the usable -virtual- address of the
+ * host controller's memory mapped I/O registers.
+ *
+ * This is where OHCI triumphs over UHCI, because good is dumb.
+ * Note how much simpler this function is than in uhci.c.
+ *
+ * OHCI hardware takes care of most of the scheduling of different
+ * transfer types with the correct prioritization for us.
+ */
+
+
+static struct ohci *alloc_ohci(void* mem_base)
+{
+	int i,j;
+	struct ohci *ohci;
+	struct ohci_hc_area *hc_area;
+	struct usb_bus *bus;
+	struct ohci_device *dev;
+	struct usb_device *usb;
+
+	/*
+	 * Here we allocate some dummy  EDs as well as the
+	 * OHCI host controller communications area.  The HCCA is just
+	 * a nice pool of memory with pointers to endpoint descriptors
+	 * for the different interrupts.
+	 *
+	 * The first page of memory  contains the HCCA and ohci structure
+	 */
+	hc_area = (struct  ohci_hc_area *) __get_free_pages(GFP_KERNEL, 1);
+	if (!hc_area)
+		return NULL;
+	memset(hc_area, 0, sizeof(*hc_area));
+    ohci = &hc_area->ohci;
+	ohci->irq = -1;
+	ohci->regs = mem_base;
+    
+	ohci->hc_area = hc_area;
+	/* Tell the controller where the HCCA is */
+	writel(virt_to_bus(&hc_area->hcca), &ohci->regs->hcca);
+	
+ 
+	/*
+	 * Initialize the ED polling "tree",  full tree;
+         * dummy eds ed[i] (hc should skip them) 
+         * i == 0 is the end of the iso list;
+		 * 1 is the   1ms node, 
+         * 2,3        2ms nodes,
+         * 4,5,6,7    4ms nodes,
+         * 8  ... 15  8ms nodes,
+         * 16 ... 31  16ms nodes,
+         * 32 ... 63  32ms nodes
+         * Sequenzes:
+		 * 32-16- 8-4-2-1-0
+         * 33-17- 9-5-3-1-0
+         * 34-18-10-6-2-1-0
+         * 35-19-11-7-3-1-0
+         * 36-20-12-4-2-1-0
+         * 37-21-13-5-3-1-0
+         * 38-22-14-6-2-1-0
+         * 39-23-15-7-3-1-0
+         * 40-24- 8-4-2-1-0
+         * 41-25- 9-5-3-1-0
+         * 42-26-10-6-2-1-0
+         *     :      :
+         * 63-31-15-7-3-1-0
+	 */
+        hc_area->ed[ED_ISO].info |=  OHCI_ED_SKIP; /* place holder, so skip it */
+        hc_area->ed[ED_ISO].next_ed =  0x0000;       /* end of iso list */
+
+        hc_area->ed[1].next_ed = virt_to_bus(&(hc_area->ed[ED_ISO]));
+        hc_area->ed[1].info |=  OHCI_ED_SKIP; /* place holder, skip it */
+	     
+        j=1;
+        for (i = 2; i < (NUM_INTS * 2); i++) {
+          	if (i >= NUM_INTS) 
+	   		 	hc_area->hcca.int_table[i - NUM_INTS] = virt_to_bus(&(hc_area->ed[i]));
+           
+          	if( i == j*4) j *= 2;
+	    	hc_area->ed[i].next_ed = virt_to_bus(&(hc_area->ed[j+ i%j]));
+            hc_area->ed[i].info |=  OHCI_ED_SKIP; /* place holder, skip it */
+        }
+
+
+	/*
+	 * for load ballancing of the interrupt branches 
+	 */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+
+	/*
+	 * Store the end of control and bulk list eds. So, we know where we can add
+	 * elements to these lists.
+	 */
+	ohci->ed_isotail     = (struct usb_ohci_ed *) &(hc_area->ed[ED_ISO]);
+        ohci->ed_controltail = NULL;
+        ohci->ed_bulktail    = NULL;
+	
+	/*
+	 * Tell the controller where the control and bulk lists are
+	 * The lists are empty now.
+	 */	
+	writel(0, &ohci->regs->ed_controlhead);
+	writel(0, &ohci->regs->ed_bulkhead);
+
+	
+	USB_ALLOC(bus, sizeof(*bus));
+	if (!bus)
+		return NULL;
+
+	memset(bus, 0, sizeof(*bus));
+
+	ohci->bus = bus;
+	bus->hcpriv = (void *) ohci;
+	bus->op = &sohci_device_operations;
+
+	 
+	usb = sohci_usb_allocate(NULL);
+	if (!usb)
+		return NULL;
+
+	dev = ohci->root_hub = usb_to_ohci(usb);
+
+	usb->bus = bus;
+	/* bus->root_hub = ohci_to_usb(ohci->root_hub); */
+	dev->ohci = ohci;
+	
+	/* Initialize the root hub */
+	 
+	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
+	usb_init_root_hub(usb);
+
+	return ohci;
+} 
+
+
+/*
+ * De-allocate all resources..
+ */
+
+static void release_ohci(struct ohci *ohci)
+{
+	int i;
+	union ep_addr_ ep_addr;
+	ep_addr.iep = 0;
+	
+    OHCI_DEBUG(printk("USB HC release ohci \n");)
+    
+	if (ohci->irq >= 0) {
+		free_irq(ohci->irq, ohci);
+		ohci->irq = -1;
+	}
+
+    /* stop hc */
+	writel(OHCI_USB_SUSPEND, &ohci->regs->control);
+		
+	/* deallocate all EDs and TDs */
+	for(i=0; i < 128; i ++) {
+		ep_addr.bep.fa = i;
+		usb_ohci_rm_function(ohci, ep_addr.iep);
+	}
+	ohci_rm_eds(ohci); /* remove eds */
+	
+    /* disconnect all devices */    
+	if(ohci->root_hub)
+		for(i = 0; i < ohci->root_hub->usb->maxchild; i++)
+			  usb_disconnect(ohci->root_hub->usb->children + i);
+	    
+    USB_FREE(ohci->root_hub->usb);
+    USB_FREE(ohci->root_hub);
+    USB_FREE(ohci->bus);
+    
+	/* unmap the IO address space */
+	iounmap(ohci->regs);
+       
+	
+	free_pages((unsigned int) ohci->hc_area, 1);
+	
+}
+
+ 
+void cleanup_drivers(void);
+
+static int ohci_roothub_thread(void * __ohci)
+{
+        struct ohci *ohci = (struct ohci *)__ohci;
+        lock_kernel(); 
+
+        /*
+         * This thread doesn't need any user-level access,
+         * so get rid of all our resources..
+         */
+        printk("ohci_roothub_thread at %p\n", &ohci_roothub_thread);
+        exit_mm(current);
+        exit_files(current);
+        exit_fs(current);
+
+
+        strcpy(current->comm, "root-hub");
+
+         
+		start_hc(ohci);
+		writel( 0x10000, &ohci->regs->roothub.status);
+		wait_ms(50); /* root hub power on */
+         do {
+#ifdef CONFIG_APM
+		if (apm_resume) {
+			apm_resume = 0;
+			start_hc(ohci);
+			continue;
+		}
+#endif
+ 	 
+         OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); )
+#ifndef VROOTHUB
+		/*	if (ohci->intrstatus & OHCI_INTR_RHSC)  */
+			{
+				int port_nr;
+	     		for(port_nr=0; port_nr< ohci->root_hub->usb->maxchild; port_nr++)
+	     			if(readl(&ohci->regs->roothub.portstatus[port_nr]) & (RH_PS_CSC | RH_PS_PRSC)) {		
+	     		 		ohci_connect_change(ohci, port_nr);
+	     		 		writel(0xffff0000, &ohci->regs->roothub.portstatus[port_nr]);
+	     		 	}
+	     		 ohci->intrstatus &= ~(OHCI_INTR_RHSC);
+	     		 writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
+	    	}
+#endif
+ 
+         interruptible_sleep_on(&root_hub);
+ 
+      	} while (!signal_pending(current)); 
+             	
+#ifdef VROOTHUB
+		ohci_del_rh_int_timer(ohci);
+#endif
+ 
+
+		cleanup_drivers();
+      /*  reset_hc(ohci); */
+	 
+        release_ohci(ohci);
+        MOD_DEC_USE_COUNT;
+
+	    printk("ohci_control_thread exiting\n");
+
+        return 0;
+}
+
+
+ 
+
+/*
+ * Increment the module usage count, start the control thread and
+ * return success.
+ */
+static int found_ohci(int irq, void* mem_base)
+{
+	int retval;
+	struct ohci *ohci;
+    OHCI_DEBUG(printk("USB HC found  ohci: irq= %d membase= %x \n", irq, (int)mem_base);)
+	/* Allocate the running OHCI structures */
+	ohci = alloc_ohci(mem_base);
+	if (!ohci) {
+	  return -ENOMEM;
+	}
+
+	reset_hc(ohci);
+
+	retval = -EBUSY;
+	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+		int pid;
+
+		MOD_INC_USE_COUNT; 
+		ohci->irq = irq;
+		 
+		pid = kernel_thread(ohci_roothub_thread, ohci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+		if (pid >= 0) 
+		 	return 0;
+		
+
+		MOD_DEC_USE_COUNT;
+		retval = pid;
+	}
+	
+	release_ohci(ohci);
+	return retval;
+}
+ 
+static int start_ohci(struct pci_dev *dev)
+{
+	unsigned int mem_base = dev->base_address[0];
+
+	/* If its OHCI, its memory */
+	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
+		return -ENODEV;
+
+	/* Get the memory address and map it for IO */
+	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	/* 
+	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
+	 * as the Alpha) [?]  What should I use instead...
+	 *
+	 * The iounmap() is done on in release_ohci.
+	 */
+	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+
+	if (!mem_base) {
+		printk("Error mapping OHCI memory\n");
+		return -EFAULT;
+	}
+
+	return found_ohci(dev->irq, (void *) mem_base);
+} 
+
+
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+	static int down = 0;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (down) {
+			printk(KERN_DEBUG "ohci: received extra suspend event\n");
+			break;
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (!down) {
+			printk(KERN_DEBUG "ohci: received bogus resume event\n");
+			break;
+		}
+		down = 0;
+		if (waitqueue_active(&root_hub)) {
+			apm_resume = 1;
+			wake_up(&root_hub);
+		}
+		break;
+	}
+	return 0;
+}
+#endif
+
+
+ int usb_mouse_init(void); 
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define ohci_hcd_init init_module
+
+#endif
+
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
+#define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10
+ 
+
+int ohci_hcd_init(void)
+{
+  int retval;
+  struct pci_dev *dev = NULL;
+ 
+  retval = -ENODEV;
+   
+  dev = NULL;
+  while((dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev))) { /* OHCI */
+    retval = start_ohci(dev);
+    if (retval < 0) break;
+
+    
+#ifdef CONFIG_USB_MOUSE
+		usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD		
+		usb_kbd_init();
+#endif		
+		hub_init();
+#ifdef CONFIG_USB_AUDIO		
+		usb_audio_init();
+#endif		
+#ifdef CONFIG_APM
+		apm_register_callback(&handle_apm_event);
+#endif
+  
+    return 0;
+  }
+  return retval;
+}
+
+void cleanup_drivers(void)
+{
+	 hub_cleanup(); 
+#ifdef CONFIG_USB_MOUSE
+	 usb_mouse_cleanup();
+#endif
+}
+
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-hcd.h linux/drivers/usb/ohci-hcd.h
--- v2.2.7/linux/drivers/usb/ohci-hcd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-hcd.h	Tue May 11 09:55:45 1999
@@ -0,0 +1,404 @@
+ /*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <wei...@vienna.at>
+ *
+ * The OHCI HCD layer is a simple but nearly complete implementation of what the
+ * USB people would call a HCD  for the OHCI. 
+ * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * 
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ Open Host Controller Interface driver for USB. ]
+ * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
+ * [ (C) Copyright 1999 Gregory P. Smith <gr...@electricrain.com> ]
+ * [ $Log: ohci.c,v $ ]
+ * [ Revision 1.1  1999/04/05 08:32:30  greg ]
+ * 
+ * 
+ * v2.1 1999/05/09 ep_addr correction, code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27
+ * ohci-hcd.h
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_OHCI_VROOTHUB
+#define VROOTHUB  
+#endif
+/* enables virtual root hub 
+ * (root hub will be managed by the hub controller 
+ *  hub.c of the alternate usb driver)
+ *  last time I did more testing without virtual root hub 
+ *  -> the virtual root hub could be more unstable now */
+ 
+ 
+  
+#ifdef OHCI_DBG
+#define OHCI_DEBUG(X) X
+#else 
+#define OHCI_DEBUG(X)
+#endif 
+
+/* for readl writel functions */
+#include <linux/list.h>
+#include <asm/io.h>
+
+/* for ED and TD structures */
+
+typedef void * __OHCI_BAG;
+typedef int (*f_handler )(void * ohci, unsigned int ep_addr, int cmd_len, void *cmd, void *data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1);
+
+
+
+struct ep_address {
+  __u8 ep;  /* bit 7: IN/-OUT, 6,5: type 10..CTRL 00..ISO  11..BULK 10..INT, 3..0: ep nr */ 
+  __u8 fa;    /* function address */
+  __u8 hc;
+  __u8 host;
+};
+
+union ep_addr_ {
+  unsigned int iep;
+  struct ep_address bep;
+};
+
+/*
+ * ED and TD descriptors has to be 16-byte aligned
+ */
+struct ohci_hw_ed {
+  __u32 info;       
+  __u32 tail_td;	/* TD Queue tail pointer */
+  __u32 head_td;	/* TD Queue head pointer */
+  __u32 next_ed;	/* Next ED */
+} __attribute((aligned(16)));
+
+
+struct usb_ohci_ed {
+  struct ohci_hw_ed hw;
+  /*  struct ohci * ohci; */
+  f_handler handler;
+  union ep_addr_ ep_addr;
+  struct usb_ohci_ed *ed_list;
+  struct usb_ohci_ed *ed_prev;
+} __attribute((aligned(32)));
+
+ /* OHCI Hardware fields */
+struct ohci_hw_td {     
+  __u32 info;
+  __u32 cur_buf;		/* Current Buffer Pointer */
+  __u32 next_td;		/* Next TD Pointer */
+  __u32 buf_end;		/* Memory Buffer End Pointer */
+} __attribute((aligned(16)));
+
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x04)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED     0x0F
+
+
+
+struct usb_ohci_td {
+  struct ohci_hw_td hw;
+  void *  buffer_start;
+  f_handler handler; 
+  struct usb_ohci_td *prev_td;
+  struct usb_ohci_ed *ep;
+  struct usb_ohci_td *next_dl_td;
+  __OHCI_BAG lw0;
+  __OHCI_BAG lw1;
+} __attribute((aligned(32)));
+
+
+
+/* TD types */
+#define BULK		0x03
+#define INT			0x01
+#define CTRL		0x02
+#define ISO			0x00
+/* TD types with direction */
+#define BULK_IN		0x07
+#define BULK_OUT	0x03
+#define INT_IN		0x05
+#define INT_OUT		0x01
+#define CTRL_IN		0x06
+#define CTRL_OUT	0x02
+#define ISO_IN		0x04
+#define ISO_OUT		0x00
+
+struct ohci_rep_td {
+  int cmd_len;
+  void * cmd;
+  void * data;
+  int data_len;
+  f_handler handler;
+  struct ohci_rep_td *next_td;
+  int ep_addr;
+  __OHCI_BAG lw0;
+  __OHCI_BAG lw1;
+  __u32 status;
+} __attribute((aligned(32))); 
+
+#define OHCI_ED_SKIP	(1 << 14)
+#define OHCI_ED_MPS	(0x7ff << 16)
+#define OHCI_ED_F_NORM	(0)
+#define OHCI_ED_F_ISOC	(1 << 15)
+#define OHCI_ED_S_LOW	(1 << 13)
+#define OHCI_ED_S_HIGH	(0)
+#define OHCI_ED_D	(3 << 11)
+#define OHCI_ED_D_IN	(2 << 11)
+#define OHCI_ED_D_OUT	(1 << 11)
+#define OHCI_ED_EN	(0xf << 7)
+#define OHCI_ED_FA	(0x7f)
+
+ 
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+    __u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+  
+
+#define ED_INT_1	1
+#define ED_INT_2	2
+#define ED_INT_4	4
+#define ED_INT_8	8
+#define ED_INT_16	16
+#define ED_INT_32	32
+#define ED_CONTROL	64
+#define ED_BULK		65
+#define ED_ISO		0	/* same as 1ms interrupt queue */
+ 
+
+/*
+ * This is the maximum number of root hub ports.  I don't think we'll
+ * ever see more than two as that's the space available on an ATX
+ * motherboard's case, but it could happen.  The OHCI spec allows for
+ * up to 15... (which is insane!)
+ * 
+ * Although I suppose several "ports" could be connected directly to
+ * internal laptop devices such as a keyboard, mouse, camera and
+ * serial/parallel ports.  hmm...  That'd be neat.
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+
+/* 
+ * Read a MMIO register and re-write it after ANDing with (m)
+ */
+#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
+
+/*
+ * Read a MMIO register and re-write it after ORing with (b)
+ */
+#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
+
+/*
+ * cmdstatus register */
+#define OHCI_CLF  0x02
+#define OHCI_BLF  0x04
+
+/*
+ * Interrupt register masks
+ */
+#define OHCI_INTR_SO	(1)
+#define OHCI_INTR_WDH	(1 << 1)
+#define OHCI_INTR_SF	(1 << 2)
+#define OHCI_INTR_RD	(1 << 3)
+#define OHCI_INTR_UE	(1 << 4)
+#define OHCI_INTR_FNO	(1 << 5)
+#define OHCI_INTR_RHSC	(1 << 6)
+#define OHCI_INTR_OC	(1 << 30)
+#define OHCI_INTR_MIE	(1 << 31)
+
+/*
+ * Control register masks
+ */
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+struct ohci {
+    	int irq;
+	    struct ohci_regs *regs;					/* OHCI controller's memory */	
+	    struct ohci_hc_area *hc_area;			/* hcca, int ed-tree, ohci itself .. */                
+        int root_hub_funct_addr;                /* Address of Root Hub endpoint */       
+        int ohci_int_load[32];                       /* load of the 32 Interrupt Chains (for load ballancing)*/     
+        struct usb_ohci_ed * ed_rm_list;        /* list of all endpoints to be removed */
+        struct usb_ohci_ed * ed_bulktail;       /* last endpoint of bulk list */
+        struct usb_ohci_ed * ed_controltail;    /* last endpoint of control list */
+        struct usb_ohci_ed * ed_isotail;        /* last endpoint of iso list */
+        struct ohci_device * root_hub;
+        struct usb_ohci_ed ed_rh_ep0;
+        struct usb_ohci_ed ed_rh_epi;
+        struct ohci_rep_td *td_rh_epi;
+        int intrstatus;
+        struct usb_ohci_ed *ed_func_ep0[128];   /* "hash"-table for ep to ed mapping */
+        struct ohci_rep_td *repl_queue;			/* for internal requests */
+        int rh_int_interval;
+        int rh_int_timer;   
+        struct usb_bus *bus;
+       
+       
+};
+
+/*
+ *  Warning: This constant must not be so large as to cause the
+ *  ohci_device structure to exceed one 4096 byte page.  Or "weird
+ *  things will happen" as the alloc_ohci() function assumes that
+ *  its less than one page at the moment.  (FIXME)
+ */
+#define NUM_TDS	4		/* num of preallocated transfer descriptors */
+#define NUM_EDS 80		/* num of preallocated endpoint descriptors */
+
+struct ohci_hc_area {
+
+	struct ohci_hcca 	hcca;		/* OHCI mem. mapped IO area 256 Bytes*/
+
+	struct ohci_hw_ed		ed[NUM_EDS];	/* Endpoint Descriptors 80 * 16  : 1280 Bytes */
+	struct ohci_hw_td		td[NUM_TDS];	/* Transfer Descriptors 2 * 32   : 64 Bytes */
+        struct ohci             ohci;
+        
+};
+struct ohci_device {
+	struct usb_device	*usb;
+	struct ohci			*ohci;
+	unsigned long		data[16];
+};
+
+#define ohci_to_usb(uhci)	((ohci)->usb)
+#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
+
+/* Debugging code */
+/*void show_ed(struct ohci_ed *ed);
+void show_td(struct ohci_td *td);
+void show_status(struct ohci *ohci); */
+
+/* hcd */
+int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int cmd_len, void  *cmd, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1); 
+struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr, int interval, int load, f_handler handler, int ep_size, int speed);
+int usb_ohci_rm_function(struct ohci * ohci, unsigned int ep_addr); 
+int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed);
+struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in);
+
+/* roothub */
+int ohci_del_rh_int_timer(struct ohci * ohci);
+int	ohci_init_rh_int_timer(struct ohci * ohci, int interval);  	
+int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int root_hub_send_irq(struct ohci * ohci, void * data, int data_len );
+int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int send_replies(struct ohci * ohci);
+
+  
+ 
+
+/* Root-Hub Register info */
+
+#define RH_PS_CCS            0x00000001   
+#define RH_PS_PES            0x00000002   
+#define RH_PS_PSS            0x00000004   
+#define RH_PS_POCI           0x00000008   
+#define RH_PS_PRS            0x00000010  
+#define RH_PS_PPS            0x00000100   
+#define RH_PS_LSDA           0x00000200    
+#define RH_PS_CSC            0x00010000 
+#define RH_PS_PESC           0x00020000   
+#define RH_PS_PSSC           0x00040000    
+#define RH_PS_OCIC           0x00080000    
+#define RH_PS_PRSC           0x00100000   
+
+
+#ifdef OHCI_DBG
+#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d\n", -- __ohci_free_cnt)
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("OHCI ALLO: %d\n", ++ __ohci_free_cnt)
+#define USB_FREE(x) kfree(x); printk("USB FREE: %d\n", -- __ohci_free1_cnt)
+#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("USB ALLO: %d\n", ++ __ohci_free1_cnt)
+static int __ohci_free_cnt = 0;
+static int __ohci_free1_cnt = 0;
+#else
+#define OHCI_FREE(x) kfree(x) 
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
+#define USB_FREE(x) kfree(x) 
+#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
+#endif
+ 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-root-hub.c linux/drivers/usb/ohci-root-hub.c
--- v2.2.7/linux/drivers/usb/ohci-root-hub.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-root-hub.c	Mon May 10 10:18:34 1999
@@ -0,0 +1,604 @@
+/*
+ * HCD (OHCI) Virtual Root Hub for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber (wei...@vienna.at)
+ *
+ * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
+ * This piece of code lets it look like it resides on the usb
+ * like the other hubs.
+ * (for anyone who wants to do a control operation on the root hub)
+ *  
+ * v2.1 1999/05/09 
+ * v2.0 1999/05/04
+ * v1.0 1999/04/27
+ * ohci-root-hub.c
+ *  
+ */
+ 
+
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+
+#include "usb.h"
+#include "ohci-hcd.h" 
+
+#ifdef VROOTHUB 
+
+#include "ohci-root-hub.h"
+
+
+static __u8 root_hub_dev_des[] =
+{
+        0x12,       /*  __u8  bLength; */
+		0x01,       /*  __u8  bDescriptorType; Device */
+		0x00,	    /*  __u16 bcdUSB; v1.0 */
+        0x01,
+		0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+		0x00,	    /*  __u8  bDeviceSubClass; */
+		0x00,       /*  __u8  bDeviceProtocol; */
+		0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+		0x00,       /*  __u16 idVendor; */
+        0x00,
+		0x00,       /*  __u16 idProduct; */
+        0x00,
+		0x00,       /*  __u16 bcdDevice; */
+        0x00,
+		0x00,       /*  __u8  iManufacturer; */
+		0x00,       /*  __u8  iProduct; */
+		0x00,       /*  __u8  iSerialNumber; */
+        0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+		0x09,       /*  __u8  bLength; */
+		0x02,       /*  __u8  bDescriptorType; Configuration */
+		0x19,       /*  __u16 wTotalLength; */
+        0x00,
+		0x01,       /*  __u8  bNumInterfaces; */
+		0x01,       /*  __u8  bConfigurationValue; */
+		0x00,       /*  __u8  iConfiguration; */
+		0x40,       /*  __u8  bmAttributes; 
+                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+		0x00,       /*  __u8  MaxPower; */
+      
+     /* interface */	  
+        0x09,       /*  __u8  if_bLength; */
+        0x04,       /*  __u8  if_bDescriptorType; Interface */
+        0x00,       /*  __u8  if_bInterfaceNumber; */
+        0x00,       /*  __u8  if_bAlternateSetting; */
+        0x01,       /*  __u8  if_bNumEndpoints; */
+        0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+        0x00,       /*  __u8  if_bInterfaceSubClass; */
+        0x00,       /*  __u8  if_bInterfaceProtocol; */
+        0x00,       /*  __u8  if_iInterface; */
+     
+     /* endpoint */
+        0x07,       /*  __u8  ep_bLength; */
+        0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+        0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+        0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+        0x40,       /*  __u16 ep_wMaxPacketSize; 64 Bytes */
+        0x00,
+        0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* 
+For OHCI we need just the  2nd Byte, so we 
+don't need this constant byte-array 
+
+static __u8 root_hub_hub_des[] =
+{ 
+        0x00,       *  __u8  bLength; *
+		0x29,       *  __u8  bDescriptorType; Hub-descriptor *
+        0x02,       *  __u8  bNbrPorts; *
+        0x00,       * __u16  wHubCharacteristics; *
+        0x00,
+        0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
+        0x00,       *  __u8  bHubContrCurrent; 0 mA *
+        0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
+        0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
+};
+*/
+
+
+int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler)
+{ 
+
+  __u32 stat;
+  __u32 rep_handler;
+  int req_reply=0;
+  union ep_addr_ ep_addr;
+  union ep_addr_ ep_addr_ret;
+        __u8 * cmd = rh_cmd;
+	__u8 * data = rh_data;
+	int i;
+	int len =leni;
+
+        __u8  bmRequestType = cmd[0];
+        __u8  bRequest      = cmd[1];
+        __u16 wValue        = cmd[3] << 8 | cmd [2];
+        __u16 wIndex        = cmd[5] << 8 | cmd [4];
+        __u16 wLength       = cmd[7] << 8 | cmd [6];
+printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8);
+for(i=0;i<8;i++)
+	printk("%2x", ((char *)rh_cmd)[i]);
+ 
+printk(" ; \n");
+
+	ep_addr_ret.iep = 0;
+	ep_addr_ret.bep.fa = ohci->root_hub_funct_addr;
+	ep_addr_ret.bep.ep =  (bmRequestType & 0x80) | 0x40;
+
+  switch (bmRequestType | bRequest << 8) {
+   /* Request Destination:
+      without flags: Device, 
+      RH_INTERFACE: interface, 
+      RH_ENDPOINT: endpoint,
+      RH_CLASS means HUB here, 
+      RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+   */
+  
+   case RH_GET_STATUS:
+     len = 2; 
+     data[0] = 0x01;
+     data[1] = 0x00;
+     req_reply = RH_ACK; 
+     break;
+   case RH_GET_STATUS | RH_INTERFACE:
+     len = 2; 
+     data[0] = 0x00;
+     data[1] = 0x00;     
+     req_reply = RH_ACK;
+     break;
+   case RH_GET_STATUS | RH_ENDPOINT:
+     len = 2; 
+     data[0] = 0x00;
+     data[1] = 0x00;     
+     req_reply = RH_ACK;
+     break;
+   case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */
+     stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */ 
+     data[0] = stat & 0xff;
+     data[1] = (stat >> 8) & 0xff;
+     data[2] = (stat >> 16) & 0xff;
+     data[3] = (stat >> 24) & 0xff;
+     len = 4;
+     req_reply = RH_ACK; 
+     break;
+   case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */
+     stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]);
+     data[0] = stat & 0xff;
+     data[1] = (stat >> 8) & 0xff;
+     data[2] = (stat >> 16) & 0xff;
+     data[3] = (stat >> 24) & 0xff;
+     len = 4;
+     req_reply = RH_ACK; 
+     printk("rh: stat %4x wIndex %4x;\n", stat , wIndex);
+     break;
+
+   case RH_CLEAR_FEATURE:
+     switch (wValue) {
+       case (RH_DEVICE_REMOTE_WAKEUP):
+       default:
+     }
+     break;
+
+   case RH_CLEAR_FEATURE | RH_ENDPOINT:  
+     switch (wValue) {
+       case (RH_ENDPOINT_STALL): 
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       default:
+     }
+     break;
+
+   case RH_CLEAR_FEATURE | RH_CLASS:
+     switch (wValue) {
+       /*     case (RH_C_HUB_LOCAL_POWER):  OHCI says: no switching of this one */
+       case (RH_C_HUB_OVER_CURRENT):
+         writel(RH_PS_OCIC, &ohci->regs->roothub.status);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       default:
+     }
+     break;
+   case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+     switch (wValue) {
+       case (RH_PORT_ENABLE):
+	     writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_SUSPEND):
+         writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_POWER):
+         writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_CONNECTION):
+         writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_ENABLE):
+         writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_SUSPEND):
+         writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_OVER_CURRENT):
+         writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_RESET):
+         writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       /*
+       case (RH_PORT_CONNECTION):
+       case (RH_PORT_OVER_CURRENT):
+       case (RH_PORT_RESET):
+       case (RH_PORT_LOW_SPEED):
+       */
+       default:
+     }
+     break;
+   case RH_SET_FEATURE:  
+     switch (wValue) {
+       case (RH_DEVICE_REMOTE_WAKEUP):
+       default:
+     }
+     break;
+
+   case RH_SET_FEATURE | RH_ENDPOINT:
+     switch (wValue) {
+       case (RH_ENDPOINT_STALL):
+       default:
+     }
+     break;
+
+   case RH_SET_FEATURE | RH_CLASS: 
+     switch (wValue) {
+       /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power 
+       case (RH_C_HUB_OVER_CURRENT): */
+      default:
+     }
+     break;
+   case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+     switch (wValue) {
+       case (RH_PORT_SUSPEND):
+         writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_RESET):
+         if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0)  /* BUG IN HUP CODE *********/
+         writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_POWER):
+         writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_ENABLE):
+         writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       /*
+       case (RH_PORT_CONNECTION):
+       case (RH_PORT_OVER_CURRENT):
+       case (RH_PORT_LOW_SPEED):
+       case (RH_C_PORT_CONNECTION):
+       case (RH_C_PORT_ENABLE):
+       case (RH_C_PORT_SUSPEND):
+       case (RH_C_PORT_OVER_CURRENT):
+       case (RH_C_PORT_RESET):
+       */
+       default:  
+     }
+     break;
+
+  case RH_SET_ADDRESS:
+     ohci->root_hub_funct_addr = wValue; 
+	/* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0;
+	 ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue; 
+	 ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */
+	 ohci->ed_rh_epi.ed_list = NULL;
+	 ohci->ed_rh_epi.ep_addr.bep.fa = wValue;
+	 ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */
+     ohci->ed_func_ep0[0]= NULL;
+     len = 0;
+     req_reply = RH_ACK;
+     break;
+
+   case RH_GET_DESCRIPTOR:
+     switch ((wValue & 0xff00) >> 8) {
+     case (0x01): /* device descriptor */
+       len = min(sizeof(root_hub_dev_des), wLength);
+       memcpy(data, root_hub_dev_des, len);
+       req_reply = RH_ACK;
+       break;
+     case (0x02): /* configuration descriptor */
+       len = min(sizeof(root_hub_config_des), wLength);
+       memcpy(data, root_hub_config_des, len);
+       req_reply = RH_ACK;
+       break;
+     case (0x03): /* string descriptors */
+     default:
+     }
+     break;
+  case RH_GET_DESCRIPTOR | RH_CLASS:
+     data[1] = 0x29;
+     stat = readl(&ohci->regs->roothub.a);  
+     data[2] = stat & 0xff;        /* number of ports */
+     data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */
+     if(data[0] > wLength) {
+       req_reply =  RH_REQ_ERR;
+       break;
+     }
+     data[3] = (stat >> 8) & 0xff;
+     data[4] = (stat >> 16) & 0xff;
+     data[5] = (stat >> 24) & 0xff;
+     data[6] = 0; /* Root Hub needs no current from bus */
+     stat = readl(&ohci->regs->roothub.b); 
+     if(data[2] <= 8) { /* less than 8 Ports */
+       data[7] = stat & 0xff;
+       data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */
+     }
+     else {
+       data[7] = stat & 0xff;
+       data[8] = (stat >> 8) & 0xff;
+       data[9] = (stat >> 16) & 0xff;  /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */
+       data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */
+     }
+     len = data[0];
+     req_reply = RH_ACK;
+     break;
+
+   case RH_SET_DESCRIPTOR:
+     break;
+
+   case RH_GET_CONFIGURATION:
+     len = 1;
+     data[0] = 0x01;
+     req_reply = RH_ACK;
+     break;
+
+   case RH_SET_CONFIGURATION: /* start it up */
+     writel( 0x10000, &ohci->regs->roothub.status);
+     /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/
+     len = 0;
+     req_reply = RH_ACK;
+     break;
+   /*  Optional or meaningless requests 
+     case RH_GET_STATE | RH_OTHER | RH_CLASS:
+     case RH_GET_INTERFACE | RH_INTERFACE:
+     case RH_SET_INTERFACE | RH_INTERFACE:
+     case RH_SYNC_FRAME | RH_ENDPOINT: 
+   */
+
+  /* Vendor Requests, we are the vendor!
+	Will the USB-Consortium give us a Vendor Id
+	for a virtual hub-device :-) ?
+     We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/ 
+
+  case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8  */
+    switch(wValue) {
+    case RH_REMOVE_EP:
+      ep_addr.iep = 0;
+      ep_addr.bep.ep = wIndex & 0xff;
+      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
+      usb_ohci_rm_function(ohci, ep_addr.iep);
+      len=0;
+      req_reply = RH_ACK;
+      break;
+    }
+    break;
+  case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */
+    switch(wValue) {
+    case RH_REMOVE_EP: 
+      ep_addr.iep = 0;
+      ep_addr.bep.ep = wIndex & 0xff;
+      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
+      usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep));
+      len=0;
+      req_reply = RH_ACK;
+      break;
+    }
+    break;
+  case RH_SET_EP | RH_ENDPOINT | RH_VENDOR:   
+    ep_addr.bep.ep = data[0];
+    ep_addr.bep.fa = data[1];
+    ep_addr.bep.hc = data[2];
+    ep_addr.bep.host = data[3];  
+    rep_handler  = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4];
+    /*  struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr,
+	struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */
+    usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]);
+    len=0;
+    req_reply = RH_ACK;
+    break;
+
+  default: 
+  }
+ printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));
+  printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));
+
+  /* if (req_reply == RH_ACK) len; */
+  queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler);
+  return 0;
+}
+
+int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){
+
+	struct ohci_rep_td *td;
+ 	struct ohci_rep_td *tmp;
+ 	union ep_addr_ ep_addr;
+ 	
+ 	td = kmalloc(sizeof(td),GFP_KERNEL);
+ 	tmp = ohci->td_rh_epi;
+ 	td->next_td = NULL;
+ 	if(tmp == NULL) { /* queue td */
+ 		ohci->td_rh_epi = td;	
+ 	}
+ 	else {
+ 		while(tmp->next_td != NULL) tmp = tmp->next_td;
+ 		tmp->next_td = td;
+ 	}
+ 	ep_addr.iep = 0;
+ 	ep_addr.bep.fa = ohci->root_hub_funct_addr;
+ 	ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */
+  	td->cmd_len = 0;
+  	td->cmd = NULL;
+  	td->data = data;
+  	td->data_len = data_len;
+  	td->handler = handler; 
+  	td->next_td = NULL;
+  	td->ep_addr = ep_addr.iep;
+	td->lw0 = lw0;
+	td->lw1 = lw1;
+	ohci_init_rh_int_timer(ohci, 255);
+	return 0;
+}
+
+
+/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */ 
+int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
+
+  int num_ports;
+  int i;
+  int ret;
+  int len;
+
+  __u8 * data = rh_data;
+
+  num_ports = readl(&ohci->regs->roothub.a) & 0xff; 
+  data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
+  ret = data[0];
+
+  for(i=0; i < num_ports; i++) {
+    data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
+    ret += data[i/8];
+  }
+  len = i/8 + 1;
+  
+  if (ret > 0) return len;
+
+  return  RH_NACK;
+}
+
+
+
+
+ 
+static struct timer_list rh_int_timer;
+
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+static void rh_int_timer_do(unsigned long ptr) {
+	int len; 
+	int interval;
+	struct ohci * ohci = (struct ohci *) ptr;
+    struct ohci_rep_td *td = ohci->td_rh_epi;
+
+	if(td != NULL) { /* if ther is a TD handle the INT request */
+		
+		len = root_hub_send_irq(ohci, td->data, td->data_len );
+		if(len > 0) {
+			ohci->td_rh_epi = td->next_td;
+			td->next_td = ohci->repl_queue; 
+			ohci->repl_queue = td;
+			send_replies(ohci);
+		}
+	}	
+	interval = ohci->rh_int_interval;
+	init_timer(& rh_int_timer);
+	rh_int_timer.function = rh_int_timer_do;
+	rh_int_timer.data = (unsigned long) ohci;
+	rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+	add_timer(&rh_int_timer);
+}
+
+/* Root Hub INTs are polled by this timer */
+int ohci_init_rh_int_timer(struct ohci * ohci, int interval) {
+
+	if(!(ohci->rh_int_timer)) { 
+		ohci->rh_int_timer = 1;
+		ohci->rh_int_interval = interval;
+		init_timer(& rh_int_timer);
+		rh_int_timer.function = rh_int_timer_do;
+		rh_int_timer.data = (unsigned long) ohci;
+		rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+		add_timer(&rh_int_timer);
+	}
+	return 0;
+}
+
+int ohci_del_rh_int_timer(struct ohci * ohci) {
+	del_timer(&rh_int_timer);
+	return 0;
+}
+/* for root hub replies, queue the reply, (it will be sent immediately now) */
+
+int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) {
+
+ struct ohci_rep_td *td;
+ int status = 0;
+ 
+printk("queue_reply ep: %x len: %x\n", ep_addr, len);
+td = kmalloc(sizeof(td), GFP_KERNEL);
+
+  if (len < 0) { status = len; len = 0;}
+  td->cmd_len = cmd_len;
+  td->cmd = cmd;
+  td->data = data;
+  td->data_len = len;
+  td->handler = handler; 
+  td->next_td = ohci->repl_queue; ohci->repl_queue = td;
+  td->ep_addr = ep_addr;
+  td->lw0 = lw0;
+  td->lw1 = lw1;
+  td->status = status;
+  send_replies(ohci);
+return 0;
+}
+
+/* for root hub replies; send the reply */
+int send_replies(struct ohci * ohci) { 
+	struct ohci_rep_td *td;
+	struct ohci_rep_td *tmp;
+
+	td = ohci->repl_queue; ohci->repl_queue = NULL;
+	while ( td != NULL) {
+		td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1); 
+		tmp = td;
+		td = td->next_td;
+	
+		kfree(tmp);
+	}
+	return 0;
+}
+ 
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-root-hub.h linux/drivers/usb/ohci-root-hub.h
--- v2.2.7/linux/drivers/usb/ohci-root-hub.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-root-hub.h	Mon May 10 10:18:34 1999
@@ -0,0 +1,71 @@
+/*
+ * HCD (OHCI) Virtual Root Hub Protocol for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber (wei...@vienna.at)
+ *
+ * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
+ * This piece of code lets it look like it resides on the bus 
+ * like the other hubs.
+ * (for anyone who wants to do a control operation on the root hub)
+ *  
+ * v1.0 1999/04/27
+ * ohci-root-hub.h
+ *  
+ */
+ 
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS			0x0500
+#define RH_GET_DESCRIPTOR		0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14  
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+ 
+#define min(a,b) (((a)<(b))?(a):(b))  
+ 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.2.7/linux/drivers/usb/ohci.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/ohci.c	Tue May 11 10:27:04 1999
@@ -29,7 +29,7 @@
X  *
X  * No filesystems were harmed in the development of this code.
X  *
- * $Id: ohci.c,v 1.11 1999/04/25 00:18:52 greg Exp $
+ * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $
X  */
X 
X #include <linux/config.h>
@@ -59,6 +59,10 @@
X 
X static struct wait_queue *ohci_configure = NULL;
X 
+#ifdef OHCI_TIMER
+static struct timer_list ohci_timer;	/* timer for root hub polling */
+#endif
+
X 
X static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
X {
@@ -69,86 +73,258 @@
X 	/* TODO Debugging code for TD failures goes here */
X 
X 	return status;
-}
+} /* ohci_td_result() */
X 
X 
X static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
X 
X /*
- * Add a TD to the end of the TD list on a given ED.  td->next_td is
- * assumed to be set correctly for the situation of no TDs already
- * being on the list (ie: pointing to NULL).
+ * Add a TD to the end of the TD list on a given ED.  If td->next_td
+ * points to any more TDs, they will be added as well (naturally).
+ * Otherwise td->next_td must be 0.
+ * 
+ * The SKIP flag will be cleared after this function.
+ *
+ * Important!  This function needs locking and atomicity as it works
+ * in parallel with the HC's DMA.  Locking ohci_edtd_lock while using
+ * the function is a must.
+ *
+ * This function can be called by the interrupt handler.
X  */
X static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
X {
-	struct ohci_td *tail = bus_to_virt(ed->tail_td);
-	struct ohci_td *head = bus_to_virt(ed->head_td);
-	unsigned long flags;
+	/* don't let the HC pull anything from underneath us */
+	ed->status |= OHCI_ED_SKIP;
X 
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-
-	if (tail == head) {	/* empty list, put it on the head */
-		head = (struct ohci_td *) virt_to_bus(td);
-		tail = 0;
+	if (ed_head_td(ed) == 0) {	/* empty list, put it on the head */
+		set_ed_head_td(ed, virt_to_bus(td));
+		ed->tail_td = 0;
X 	} else {
+		struct ohci_td *tail, *head;
+		head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed));
+		tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td);
X 		if (!tail) {	/* no tail, single element list */
X 			td->next_td = head->next_td;
X 			head->next_td = virt_to_bus(td);
-			tail = (struct ohci_td *) virt_to_bus(td);
+			ed->tail_td = virt_to_bus(td);
X 		} else {	/* append to the list */
X 			td->next_td = tail->next_td;
X 			tail->next_td = virt_to_bus(td);
-			tail = (struct ohci_td *) virt_to_bus(td);
+			ed->tail_td = virt_to_bus(td);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 23'
echo 'File patch-2.2.8 is continued in part 24'
echo 24 > _shar_seq_.tmp
#!/bin/sh
# this is part 24 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 24; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 		}
X 	}
-	/* save the reverse link */
-	td->ed_bus = virt_to_bus(ed);
X 
-	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	/* save the ED link in each of the TDs added */
+	td->ed = ed;
+	while (td->next_td != 0) {
+		td = bus_to_virt(td->next_td);
+		td->ed = ed;
+	}
+
+	/* turn off the SKIP flag */
+	ed->status &= ~OHCI_ED_SKIP;
X } /* ohci_add_td_to_ed() */
X 
X 
+inline void ohci_start_control(struct ohci *ohci)
+{
+	/* tell the HC to start processing the control list */
+	writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
+}
+
+inline void ohci_start_bulk(struct ohci *ohci)
+{
+	/* tell the HC to start processing the bulk list */
+	writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
+}
+
+inline void ohci_start_periodic(struct ohci *ohci)
+{
+	/* enable processing periodc transfers starting next frame */
+	writel_set(OHCI_USB_PLE, &ohci->regs->control);
+}
+
+inline void ohci_start_isoc(struct ohci *ohci)
+{
+	/* enable processing isoc. transfers starting next frame */
+	writel_set(OHCI_USB_IE, &ohci->regs->control);
+}
+
X /*
- *  Remove a TD from the given EDs TD list
+ * Add an ED to the hardware register ED list pointed to by hw_listhead_p
+ */
+static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p)
+{
+	__u32 listhead;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	
+	listhead = readl(hw_listhead_p);
+
+	/* if the list is not empty, insert this ED at the front */
+	/* XXX should they go on the end? */
+	if (listhead) {
+		ed->next_ed = listhead;
+	}
+
+	/* update the hardware listhead pointer */
+	writel(virt_to_bus(ed), hw_listhead_p);
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_add_ed() */
+
+
+/*
+ *  Put another control ED on the controller's list
+ */
+void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_add_ed_to_hw(ed, &ohci->regs->ed_controlhead);
+	ohci_start_control(ohci);
+} /* ohci_add_control_ed() */
+
+
+#if 0
+/*
+ *  Put another control ED on the controller's list
+ */
+void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
+{
+	ohci_add_ed_to_hw(ed, /* XXX */);
+	ohci_start_periodic(ohci);
+} /* ohci_add_control_ed() */
+#endif
+
+
+/*
+ *  Remove an ED from the HC list whos bus headpointer is pointed to
+ *  by hw_listhead_p
+ *  
+ *  Note that the SKIP bit is left on in the removed ED.
+ */
+void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p)
+{
+	unsigned long flags;
+	struct ohci_ed *cur;
+	__u32 bus_ed = virt_to_bus(ed);
+	__u32 bus_cur;
+
+	if (ed == NULL || !bus_ed)
+		return;
+
+	/* tell the controller this skip ED */
+	ed->status |= OHCI_ED_SKIP;
+
+	bus_cur = readl(hw_listhead_p);
+
+	if (bus_cur == 0)
+		return;   /* the list is already empty */
+
+	cur = bus_to_virt(bus_cur);
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+	/* if its the head ED, move the head */
+	if (bus_cur == bus_ed) {
+		writel(cur->next_ed, hw_listhead_p);
+	} else if (cur->next_ed != 0) {
+		struct ohci_ed *prev;
+
+		/* walk the list and unlink the ED if found */
+		for (;;) {
+			prev = cur;
+			cur = bus_to_virt(cur->next_ed);
+
+			if (virt_to_bus(cur) == bus_ed) {
+				/* unlink from the list */
+				prev->next_ed = cur->next_ed;
+				break;
+			}
+
+			if (cur->next_ed == 0)
+				break;
+		}
+	}
+
+	/* clear any links from the ED for safety */
+	ed->next_ed = 0;
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_remove_ed_from_hw() */
+
+/*
+ *  Remove an ED from the controller's control list.  Note that the SKIP bit
+ *  is left on in the removed ED.
+ */
+inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead);
+}
+
+/*
+ *  Remove an ED from the controller's bulk list.  Note that the SKIP bit
+ *  is left on in the removed ED.
+ */
+inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead);
+}
+
+
+/*
+ *  Remove a TD from the given EDs TD list.
X  */
X static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
X {
-	struct ohci_td *head = bus_to_virt(ed->head_td);
-	struct ohci_td *tmp_td;
X 	unsigned long flags;
+	struct ohci_td *head_td;
+
+	if ((td == NULL) || (ed == NULL))
+		return;
X 
X 	spin_lock_irqsave(&ohci_edtd_lock, flags);
X 
+	if (ed_head_td(ed) == 0)
+		return;
+
X 	/* set the "skip me bit" in this ED */
-	writel_set(OHCI_ED_SKIP, ed->status);
+	ed->status |= OHCI_ED_SKIP;
X 
X 	/* XXX Assuming this list will never be circular */
X 
-	if (td == head) {
-		/* unlink this TD; it was at the beginning */
-		ed->head_td = head->next_td;
-	}
-
-	tmp_td = head;
-	head = (struct ohci_td *) ed->head_td;
-	
-	while (head != NULL) {
+	head_td = bus_to_virt(ed_head_td(ed));
+	if (virt_to_bus(td) == ed_head_td(ed)) {
+		/* It's the first TD, remove it. */
+		set_ed_head_td(ed, head_td->next_td);
+	} else {
+		struct ohci_td *prev_td, *cur_td;
X 
-		if (td == head) {
-			/* unlink this TD from the middle or end */
-			tmp_td->next_td = head->next_td;
+		/* FIXME: collapse this into a nice simple loop :) */
+		if (head_td->next_td != 0) {
+			prev_td = head_td;
+			cur_td = bus_to_virt(head_td->next_td);
+			for (;;) {
+				if (td == cur_td) {
+					/* remove it */
+					prev_td->next_td = cur_td->next_td;
+					break;
+				}
+				if (cur_td->next_td == 0)
+					break;
+				prev_td = cur_td;
+				cur_td = bus_to_virt(cur_td->next_td);
+			}
X 		}
-
-		tmp_td = head;
-		head = bus_to_virt(head->next_td);
X 	}
X 
-	td->next_td = virt_to_bus(NULL);  /* remove links to ED list */
+	td->next_td = 0;  /* remove the TDs links */
+	td->ed = NULL;
X 
-	/* XXX mark this TD for possible cleanup? */
+	/* TODO return this TD to the pool of free TDs */
X 
X 	/* unset the "skip me bit" in this ED */
-	writel_mask(~(__u32)OHCI_ED_SKIP, ed->status);
+	ed->status &= ~OHCI_ED_SKIP;
X 
X 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
X } /* ohci_remove_td_from_ed() */
@@ -165,60 +341,67 @@
X 	int idx;
X 
X 	for (idx=0; idx < NUM_TDS; idx++) {
-		if (td_done(dev->td[idx].info)) {
-			/* XXX should this also zero out the structure? */
-			/* mark all new TDs as unaccessed */
-			dev->td[idx].info = OHCI_TD_CC_NEW;
-			return &dev->td[idx];
+		if (!td_allocated(dev->td[idx])) {
+			struct ohci_td *new_td = &dev->td[idx];
+			/* zero out the TD */
+			memset(new_td, 0, sizeof(*new_td));
+			/* mark the new TDs as unaccessed */
+			new_td->info = OHCI_TD_CC_NEW;
+			/* mark it as allocated */
+			allocate_td(new_td);
+			return new_td;
X 		}
X 	}
X 
+	printk("usb-ohci error: unable to allocate a TD\n");
X 	return NULL;
X } /* ohci_get_free_td() */
X 
X 
-/**********************************
- * OHCI interrupt list operations *
- **********************************/
-static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
-
-static void ohci_add_irq_list(struct ohci *ohci, struct ohci_td *td, usb_device_irq completed, void *dev_id)
+/*
+ *  Initialize a TD
+ *
+ * 	dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
+ * 	toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1
+ */
+inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
X {
-	unsigned long flags;
+	/* hardware fields */
+	td->info = OHCI_TD_CC_NEW |
+		(dir & OHCI_TD_D) |
+		(toggle & OHCI_TD_DT) |
+		flags;
+	td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data);
+	td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1;
X 
-	/* save the irq in our private portion of the TD */
-	td->completed = completed;
+	/* driver fields */
+	td->data = data;
X 	td->dev_id = dev_id;
+	td->completed = completed;
X 
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_add(&td->irq_list, &ohci->interrupt_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
-} /* ohci_add_irq_list() */
+	return td;
+} /* ohci_fill_new_td() */
X 
-static void ohci_remove_irq_list(struct ohci_td *td)
-{
-	unsigned long flags;
X 
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_del(&td->irq_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
-} /* ohci_remove_irq_list() */
+/**********************************
+ * OHCI interrupt list operations *
+ **********************************/
X 
X /*
X  * Request an interrupt handler for one "pipe" of a USB device.
X  * (this function is pretty minimal right now)
X  *
X  * At the moment this is only good for input interrupts. (ie: for a
- * mouse)
+ * mouse or keyboard)
X  *
- * period is desired polling interval in ms.  The closest, shorter
+ * Period is desired polling interval in ms.  The closest, shorter
X  * match will be used.  Powers of two from 1-32 are supported by OHCI.
X  */
X static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
X 	usb_device_irq handler, int period, void *dev_id)
X {
X 	struct ohci_device *dev = usb_to_ohci(usb);
-	struct ohci_td *td = dev->td;	/* */
+	struct ohci_td *td;
X 	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
X 
X 	/*
@@ -239,42 +422,68 @@
X 		usb_pipe_endpdev(pipe) |
X 		OHCI_ED_F_NORM;
X 
+	td = ohci_get_free_td(dev);
+	/* FIXME: check for NULL */
+
+	/* Fill in the TD */
+	ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
+			TOGGLE_AUTO,
+			OHCI_TD_ROUND,
+			dev->data, DATA_BUF_LEN,
+			dev_id, handler);
X 	/*
-	 * Set the not accessed condition code, allow odd sized data,
-	 * and set the data transfer direction.
+	 * TODO: be aware that OHCI won't advance out of the 4kb
+	 * page cur_buf started in.  It'll wrap around to the start
+	 * of the page...  annoying or useful? you decide.
+	 *
+	 * We should make sure dev->data doesn't cross a page...
X 	 */
-	td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
-		td_set_dir_out(usb_pipeout(pipe));
X 
-	/* point it to our data buffer */
-	td->cur_buf = virt_to_bus(dev->data);
+	/* FIXME: this just guarantees that its the end of the list */
+	td->next_td = 0;
X 
-	/* FIXME: we're only using 1 TD right now! */
-	td->next_td = virt_to_bus(&td);
+	/* Linus did this. see asm/system.h; scary concept... I don't
+	 * know if its needed here or not but it won't hurt. */
+	wmb();
X 
X 	/*
-	 * FIXME: be aware that OHCI won't advance out of the 4kb
-	 * page cur_buf started in.  It'll wrap around to the start
-	 * of the page...  annoying or useful? you decide.
-	 *
-	 * A pointer to the last *byte* in the buffer (ergh.. we get
-	 * to work around C's pointer arithmatic here with a typecast)
+	 *  Put the TD onto our ED
X 	 */
-	td->buf_end = virt_to_bus(((u8*)(dev->data + DATA_BUF_LEN)) - 1);
+	{
+		unsigned long flags;
+		spin_lock_irqsave(&ohci_edtd_lock, flags);
+		ohci_add_td_to_ed(td, interrupt_ed);
+		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	}
X 
-	/* does this make sense for ohci?.. time to think.. */
-	ohci_add_irq_list(dev->ohci, td, handler, dev_id);
-	wmb();     /* found in asm/system.h; scary concept... */
-	ohci_add_td_to_ed(td, interrupt_ed);
+#if 0
+	/* Assimilate the new ED into the collective */
+	/*
+	 *  When dynamic ED allocation is done, this call will be
+	 *  useful.  For now, the correct ED already on the
+	 *  controller's proper periodic ED lists was chosen above.
+	 */
+	ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+#else
+	/* enable periodic (interrupt) transfers on the HC */
+	ohci_start_periodic(dev->ohci);
+#endif
X 
X 	return 0;
X } /* ohci_request_irq() */
X 
+
X /*
X  * Control thread operations:
X  */
X static struct wait_queue *control_wakeup;
X 
+/*
+ *  This is the handler that gets called when a control transaction
+ *  completes.
+ *
+ *  This function is called from the interrupt handler.
+ */
X static int ohci_control_completed(int stats, void *buffer, void *dev_id)
X {
X 	wake_up(&control_wakeup);
@@ -283,41 +492,16 @@
X 
X 
X /*
- * Run a control transaction from the root hub's control endpoint.
- * The passed in TD is the control transfer's Status TD.
- */
-static int ohci_run_control(struct ohci_device *dev, struct ohci_td *status_td)
-{
-	struct wait_queue wait = { current, NULL };
-	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-
-	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&control_wakeup, &wait);
-
-	ohci_add_irq_list(dev->ohci, status_td, ohci_control_completed, NULL);
-	ohci_add_td_to_ed(status_td, control_ed);
-
-	/* FIXME? isn't this a little gross */
-	schedule_timeout(HZ/10);
-
-	ohci_remove_irq_list(status_td);
-	ohci_remove_td_from_ed(status_td, control_ed);
-
-	return ohci_td_result(dev, status_td);
-} /* ohci_run_control() */
-
-/*
X  * Send or receive a control message on a "pipe"
X  *
+ * The cmd parameter is a pointer to the 8 byte setup command to be
+ * sent.  FIXME:  This is a devrequest in usb.h.  The function
+ * should be updated to accept a devrequest* instead of void*..
+ *
X  * A control message contains:
X  *   - The command itself
- *   - An optional data phase
+ *   - An optional data phase (if len > 0)
X  *   - Status complete phase
- *
- * The data phase can be an arbitrary number of TD's.  Currently since
- * we use statically allocated TDs if too many come in we'll just
- * start tossing them and printk() some warning goo...  Most control
- * messages won't have much data anyways.
X  */
X static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
X {
@@ -330,10 +514,12 @@
X 	 * anyways? ;)
X 	 */
X 	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-	struct ohci_td *control_td;
-	struct ohci_td *data_td;
-	struct ohci_td *last_td;
-	__u32 data_td_info;
+	struct ohci_td *setup_td, *data_td, *status_td;
+	struct wait_queue wait = { current, NULL };
+
+#if 0
+	printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
+#endif
X 
X 	/*
X 	 * Set the max packet size, device speed, endpoint number, usb
@@ -351,95 +537,174 @@
X 	 */
X 
X 	/* get a TD to send this control message with */
-	control_td = ohci_get_free_td(dev);
+	setup_td = ohci_get_free_td(dev);
X 	/* TODO check for NULL */
X 
X 	/*
X 	 * Set the not accessed condition code, allow odd sized data,
X 	 * and set the data transfer type to SETUP.  Setup DATA always
X 	 * uses a DATA0 packet.
-	 */
-	control_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
-		OHCI_TD_D_SETUP | OHCI_TD_IOC_OFF | td_force_toggle(0);
-
-	/* point it to the command */
-	control_td->cur_buf = virt_to_bus(cmd);
+	 *
+	 * The setup packet contains a devrequest (usb.h) which
+	 * will always be 8 bytes long.  FIXME: the cmd parameter
+	 * should be a pointer to one of these instead of a void* !!!
+	 */
+	ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
+			OHCI_TD_IOC_OFF,
+			cmd, 8,		/* cmd is always 8 bytes long */
+			NULL, NULL);
X 
-	/* link to a free TD for the control data input */
+	/* allocate the next TD */
X 	data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-	control_td->next_td = virt_to_bus(data_td);
+
+	/* link to the next TD */
+	setup_td->next_td = virt_to_bus(data_td);
+
+	if (len > 0) {
+
+		/* build the Control DATA TD, it starts with a DATA1. */
+		ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)),
+				TOGGLE_DATA1,
+				OHCI_TD_ROUND | OHCI_TD_IOC_OFF,
+				data, len,
+				NULL, NULL);
+
+		/*
+		 * XXX we should check that the data buffer doesn't
+		 * cross a 4096 byte boundary.  If so, it needs to be
+		 * copied into a single 4096 byte aligned area for the
+		 * OHCI's TD logic to see it all, or multiple TDs need
+		 * to be made for each page.
+		 *
+		 * It's not likely a control transfer will run into
+		 * this problem.. (famous last words)
+		 */
+
+		status_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+		data_td->next_td = virt_to_bus(status_td);
+	} else {
+		status_td = data_td; /* no data_td, use it for status */
+	}
+
+	/* The control status packet always uses a DATA1 */
+	ohci_fill_new_td(status_td,
+			td_set_dir_in(usb_pipeout(pipe) | (len == 0)),
+			TOGGLE_DATA1,
+			0,
+			NULL, 0,
+			NULL, ohci_control_completed);
+	status_td->next_td = 0; /* end of TDs */
X 
X 	/*
-	 * Build the DATA TDs
+	 * Start the control transaction..
X 	 */
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&control_wakeup, &wait);
X 
-	data_td_info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | OHCI_TD_IOC_OFF |
-		td_set_dir_out(usb_pipeout(pipe));
-
-	while (len > 0) {
-		int pktsize = len;
-		struct ohci_td *tmp_td;
+	/*
+	 * Add the chain of 2-3 control TDs to the control ED's TD list
+	 */
+	{
+		unsigned long flags;
+		spin_lock_irqsave(&ohci_edtd_lock, flags);
+		ohci_add_td_to_ed(setup_td, control_ed);
+		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	}
+
+#if 0
+	/* complete transaction debugging output (before) */
+	printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
+	show_ohci_ed(control_ed);
+	printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td));
+	show_ohci_td(setup_td);
+	if (data_td != status_td) {
+		printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td));
+		show_ohci_td(data_td);
+	}
+	printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
+	show_ohci_td(status_td);
+#endif
X 
-		if (pktsize > usb_maxpacket(pipe))
-			pktsize = usb_maxpacket(pipe);
+	/* Give the ED to the HC */
+	ohci_add_control_ed(dev->ohci, control_ed);
X 
-		/* set the data transaction type */
-		data_td->info = data_td_info;
-		/* point to the current spot in the data buffer */
-		data_td->cur_buf = virt_to_bus(data);
-		/* point to the end of this data */
-		data_td->buf_end = virt_to_bus(data+pktsize-1);
+	/* FIXME:
+	 * this should really check to see that the transaction completed.
+	 */
+	schedule_timeout(HZ/10);
X 
-		/* allocate the next TD */
-		tmp_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-		data_td->next_td = virt_to_bus(tmp_td);
-		data_td = tmp_td;
+	remove_wait_queue(&control_wakeup, &wait);
X 
-		/* move on.. */
-		data += pktsize;
-		len -= pktsize;
+#if 0
+	/* complete transaction debugging output (after) */
+	printk(KERN_DEBUG " (after) Control ED:\n");
+	show_ohci_ed(control_ed);
+	printk(KERN_DEBUG " (after) Setup TD:\n");
+	show_ohci_td(setup_td);
+	if (data_td != status_td) {
+		printk(KERN_DEBUG " (after) Data TD:\n");
+		show_ohci_td(data_td);
X 	}
+	printk(KERN_DEBUG " (after) Status TD:\n");
+	show_ohci_td(status_td);
+#endif
X 
-	/* point it at the newly allocated TD from above */
-	last_td = data_td;
+	/* clean up incase it failed */
+	/* XXX only do this if their ed pointer still points to control_ed
+	 * incase they've been reclaimed and used by something else
+	 * already. -greg */
+	ohci_remove_td_from_ed(setup_td, control_ed);
+	ohci_remove_td_from_ed(data_td, control_ed);
+	ohci_remove_td_from_ed(status_td, control_ed);
X 
-	/* The control status packet always uses a DATA1 */
-	last_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | td_force_toggle(1);
-	last_td->next_td = 0; /* end of TDs */
-	last_td->cur_buf = 0; /* no data in this packet */
-	last_td->buf_end = 0;
+	/* remove the control ED */
+	ohci_remove_control_ed(dev->ohci, control_ed);
X 
-	/*
-	 * Start the control transaction.. give it the last TD so the
-	 * result can be returned.
-	 */
-	return ohci_run_control(dev, last_td);
+#if 0
+	printk(KERN_DEBUG "leaving ohci_control_msg\n");
+#endif
+
+	return ohci_td_result(dev, status_td);
X } /* ohci_control_msg() */
X 
X 
+/*
+ * Allocate a new USB device to be attached to an OHCI controller
+ */
X static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
X {
X 	struct usb_device *usb_dev;
X 	struct ohci_device *dev;
X 
+	/*
+	 * Allocate the generic USB device
+	 */
X 	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
X 	if (!usb_dev)
X 		return NULL;
X 
X 	memset(usb_dev, 0, sizeof(*usb_dev));
X 
+	/*
+	 * Allocate an OHCI device (EDs and TDs for this device)
+	 */
X 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
X 	if (!dev) {
X 		kfree(usb_dev);
X 		return NULL;
X 	}
X 
-	/* Initialize "dev" */
X 	memset(dev, 0, sizeof(*dev));
X 
+	/*
+	 * Link them together
+	 */
X 	usb_dev->hcpriv = dev;
X 	dev->usb = usb_dev;
X 
+	/*
+	 * Link the device to its parent (hub, etc..) if any.
+	 */
X 	usb_dev->parent = parent;
X 
X 	if (parent) {
@@ -448,8 +713,14 @@
X 	}
X 
X 	return usb_dev;
-}
+} /* ohci_usb_allocate() */
+
X 
+/*
+ * Free a usb device.
+ *
+ * TODO This function needs to take better care of the EDs and TDs, etc.
+ */
X static int ohci_usb_deallocate(struct usb_device *usb_dev)
X {
X 	kfree(usb_to_ohci(usb_dev));
@@ -457,6 +728,7 @@
X 	return 0;
X }
X 
+
X /*
X  * functions for the generic USB driver
X  */
@@ -467,42 +739,92 @@
X 	ohci_request_irq,
X };
X 
+
X /*
- * Reset an OHCI controller
+ * Reset an OHCI controller.  Returns >= 0 on success.
+ *
+ * Afterwards the HC will be in the "suspend" state which prevents you
+ * from writing to some registers.  Bring it to the operational state
+ * ASAP.
X  */
-static void reset_hc(struct ohci *ohci)
+static int reset_hc(struct ohci *ohci)
X {
-	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
-	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
+	int timeout = 1000;  /* prevent an infinite loop */
+
+#if 0
+	printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci);
+#endif
+
+	writel(~0x0, &ohci->regs->intrdisable);    /* Disable HC interrupts */
+	writel(1, &ohci->regs->cmdstatus);	   /* HC Reset */
X 	writel_mask(0x3f, &ohci->regs->control);   /* move to UsbReset state */
+
+	while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) {
+		if (!--timeout) {
+			printk("usb-ohci: USB HC reset timed out!\n");
+			return -1;
+		}
+		udelay(1);
+	}
+
+	printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
+
+	return 0;
X } /* reset_hc() */
X 
X 
X /*
- * Reset and start an OHCI controller
+ * Reset and start an OHCI controller.  Returns >= 0 on success.
X  */
-static void start_hc(struct ohci *ohci)
+static int start_hc(struct ohci *ohci)
X {
-	int timeout = 1000;	/* used to prevent an infinite loop. */
+	int ret = 0;
+	int fminterval;
X 
-	reset_hc(ohci);
+	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+#if 0
+	printk(KERN_DEBUG "entering start_hc %p\n", ohci);
+#endif
X 
-	while ((readl(&ohci->regs->control) & 0xc0) == 0) {
-		if (!--timeout) {
-			printk("USB HC Reset timed out!\n");
-			break;
-		}
-	}
+	if (reset_hc(ohci) < 0)
+		return -1;
+
+	/* restore registers cleared by the reset */
+	writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca);
+
+	/*
+	 * XXX Should fminterval also be set here?
+	 * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
+	 */
+	fminterval |= (0x2edf << 16);
+	writel(fminterval, &ohci->regs->fminterval);
+	/* Start periodic transfers at 90% of fminterval (fmremaining
+	 * counts down; this will put them in the first 10% of the
+	 * frame). */
+	writel((0x2edf*9)/10, &ohci->regs->periodicstart);
X 
+	/*
+	 * FNO (frame number overflow) could be enabled...  they
+	 * occur every 32768 frames (every 32-33 seconds).  This is
+	 * useful for debugging and as a bus heartbeat. -greg
+	 */
X 	/* Choose the interrupts we care about */
-	writel( OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_SF |
-		OHCI_INTR_WDH | OHCI_INTR_SO | OHCI_INTR_UE |
-		OHCI_INTR_FNO,
+	writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */
+		OHCI_INTR_WDH | OHCI_INTR_FNO,
X 		&ohci->regs->intrenable);
X 
X 	/* Enter the USB Operational state & start the frames a flowing.. */
X 	writel_set(OHCI_USB_OPER, &ohci->regs->control);
+	
+	/* Enable control lists */
+	writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
+
+	/* Turn on power to the root hub ports (thanks Roman!) */
+	writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
+
+	printk("usb-ohci: host controller operational\n");
X 
+	return ret;
X } /* start_hc() */
X 
X 
@@ -511,23 +833,20 @@
X  */
X static void ohci_reset_port(struct ohci *ohci, unsigned int port)
X {
-	short ms;
X 	int status;
X 
X 	/* Don't allow overflows. */
X 	if (port >= MAX_ROOT_PORTS) {
-		printk("Bad port # passed to ohci_reset_port\n");
+		printk("usb-ohci: bad port #%d in ohci_reset_port\n", port);
X 		port = MAX_ROOT_PORTS-1;
X 	}
X 
X 	writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);  /* Reset */
X 
X 	/*
-	 * Get the time required for a root hub port to reset and wait
-	 * it out (adding 1ms for good measure).
+	 * Wait for the reset to complete.
X 	 */
-	ms = (readl(&ohci->regs->roothub.a) >> 24) * 2 + 1;
-	wait_ms(ms);
+	wait_ms(10);
X 
X 	/* check port status to see that the reset completed */
X 	status = readl(&ohci->regs->roothub.portstatus[port]);
@@ -555,6 +874,8 @@
X 	void *portaddr = &ohci->regs->roothub.portstatus[port];
X 	int portstatus;	
X 
+	printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port);
+
X 	/*
X 	 * Because of the status change we have to forget
X 	 * everything we think we know about the device
@@ -593,6 +914,7 @@
X 	 * Do generic USB device tree processing on the new device.
X 	 */
X 	usb_new_device(usb_dev);
+
X } /* ohci_connect_change() */
X 
X 
@@ -603,66 +925,241 @@
X  */
X static void ohci_check_configuration(struct ohci *ohci)
X {
+	struct ohci_regs *regs = ohci->regs;
X 	int num = 0;
X 	int maxport = readl(&ohci->regs->roothub) & 0xff;
X 
+#if 1
+	printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci);
+#endif
+
X 	do {
-		if (readl(ohci->regs->roothub.portstatus[num]) & PORT_CSC)
+		if (readl(®s->roothub.portstatus[num]) & PORT_CSC) {
+			/* reset the connect status change bit */
+			writel(PORT_CSC, ®s->roothub.portstatus[num]);
+			/* check the port for a nifty device */
X 			ohci_connect_change(ohci, num);
+		}
X 	} while (++num < maxport);
+
+#if 0
+	printk(KERN_DEBUG "leaving ohci_check_configuration %p\n", ohci);
+#endif
X } /* ohci_check_configuration() */
X 
X 
+
+/*
+ * Check root hub port status and wake the control thread up if
+ * anything has changed.
+ *
+ * This function is called from the interrupt handler.
+ */
+static void ohci_root_hub_events(struct ohci *ohci)
+{
+	if (waitqueue_active(&ohci_configure)) {
+		int num = 0;
+		int maxport = ohci->root_hub->usb->maxchild;
+
+		do {
+			if (readl(&ohci->regs->roothub.portstatus[num]) &
+					PORT_CSC) {
+				if (waitqueue_active(&ohci_configure))
+					wake_up(&ohci_configure);
+				return;
+			}
+		} while (++num < maxport);
+	}
+} /* ohci_root_hub_events() */
+
+
+/*
+ * The done list is in reverse order; we need to process TDs in the
+ * order they were finished (FIFO).  This function builds the FIFO
+ * list using the next_dl_td pointer.
+ *
+ * This function originally by Roman Weissgaerber (wei...@vienna.at)
+ *
+ * This function is called from the interrupt handler.
+ */
+static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci)
+{
+	__u32 td_list_hc;
+	struct ohci_hcca *hcca = ohci->root_hub->hcca;
+	struct ohci_td *td_list = NULL;
+	struct ohci_td *td_rev = NULL;
+  	
+	td_list_hc = hcca->donehead & 0xfffffff0;
+	hcca->donehead = 0;
+
+ 	while(td_list_hc) {
+		td_list = (struct ohci_td *) bus_to_virt(td_list_hc);
+		td_list->next_dl_td = td_rev;
+			
+		td_rev = td_list;
+		td_list_hc = td_list->next_td & 0xfffffff0;
+	}
+
+	return td_list;
+} /* ohci_reverse_donelist() */
+
+
+/*
+ * Collect this interrupt's goodies off of the list of finished TDs
+ * that the OHCI controller is kind enough to setup for us.
+ *
+ * This function is called from the interrupt handler.
+ */
+static void ohci_reap_donelist(struct ohci *ohci)
+{
+	struct ohci_td *td;		/* used for walking the list */
+
+	spin_lock(&ohci_edtd_lock);
+
+	/* create the FIFO ordered donelist */
+	td = ohci_reverse_donelist(ohci);
+
+	while (td != NULL) {
+		struct ohci_td *next_td = td->next_dl_td;
+
+		/* FIXME: munge td->info into a future standard status format */
+		/* Check if TD should be re-queued */
+		if ((td->completed != NULL) &&
+		    (td->completed(OHCI_TD_CC_GET(td->info), td->data, td->dev_id)))
+		{
+			/* Mark the TD as active again:
+			 * Set the not accessed condition code
+			 * FIXME: should this reset OHCI_TD_ERRCNT?
+			 */
+			td->info |= OHCI_TD_CC_NEW;
+
+			/* point it back to the start of the data buffer */
+			td->cur_buf = virt_to_bus(td->data);
+
+			/* XXX disabled for debugging reasons right now.. */
+			/* insert it back on its ED */
+			ohci_add_td_to_ed(td, td->ed);
+		} else {
+			/* return it to the pool of free TDs */
+			ohci_free_td(td);
+		}
+
+		td = next_td;
+	}
+
+	spin_unlock(&ohci_edtd_lock);
+} /* ohci_reap_donelist() */
+
+
+#if 0
+static int in_int = 0;
+#endif
X /*
X  * Get annoyed at the controller for bothering us.
+ * This pretty much follows the OHCI v1.0a spec, section 5.3.
X  */
X static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
X {
X 	struct ohci *ohci = __ohci;
X 	struct ohci_regs *regs = ohci->regs;
X 	struct ohci_hcca *hcca = ohci->root_hub->hcca;
-	__u32 donehead = hcca->donehead;
+	__u32 status, context;
X 
-	/*
-	 * Check the interrupt status register if needed
-	 */
-	if (!donehead || (donehead & 1)) {
-		__u32 intrstatus = readl(®s->intrstatus);
+#if 0
+	/* for debugging to keep IRQs from running away. */
+	if (in_int >= 2)
+		return;
+	++in_int;
+	return;
+#endif
X 
-		/*
-		 * XXX eek! printk's in an interrupt handler.  shoot me!
-		 */
-		if (intrstatus & OHCI_INTR_SO) {
-			printk(KERN_DEBUG "usb-ohci: scheduling overrun\n");
-		}
-		if (intrstatus & OHCI_INTR_RD) {
-			printk(KERN_DEBUG "usb-ohci: resume detected\n");
-		}
-		if (intrstatus & OHCI_INTR_UE) {
-			printk(KERN_DEBUG "usb-ohci: unrecoverable error\n");
+	/* Save the status of the interrupts that are enabled */
+	status = readl(®s->intrstatus);
+	status &= readl(®s->intrenable);
+
+
+	/* make context = the interrupt status bits that we care about */
+	if (hcca->donehead != 0) {
+		context = OHCI_INTR_WDH;   /* hcca donehead needs processing */
+		if (hcca->donehead & 1) {
+			context |= status;  /* other status change to check */
X 		}
-		if (intrstatus & OHCI_INTR_OC) {
-			printk(KERN_DEBUG "usb-ohci: ownership change?\n");
+	} else {
+		context = status;
+		if (!context) {
+			/* TODO increment a useless interrupt counter here */
+			return;
X 		}
+	}
X 
-		if (intrstatus & OHCI_INTR_RHSC) {
-			/* TODO Process events on the root hub */
-		}
+	/* Disable HC interrupts */
+	writel(OHCI_INTR_MIE, ®s->intrdisable);
+
+	/* Process the done list */
+	if (context & OHCI_INTR_WDH) {
+		/* See which TD's completed.. */
+		ohci_reap_donelist(ohci);
+
+		/* reset the done queue and tell the controller */
+		hcca->donehead = 0;
+		writel(OHCI_INTR_WDH, ®s->intrstatus);
+
+		context &= ~OHCI_INTR_WDH;  /* mark this as checked */
X 	}
X 
-	/*
-	 * Process the done list
-	 */
-	if (donehead &= ~0x1) {
-		/*
-		 * TODO See which TD's completed..
+	/* Process any root hub status changes */
+	if (context & OHCI_INTR_RHSC) {
+		/* Wake the thread to process root hub events */
+		if (waitqueue_active(&ohci_configure))
+			wake_up(&ohci_configure);
+
+		writel(OHCI_INTR_RHSC, ®s->intrstatus);
+		/* 
+		 * Don't unset RHSC in context; it should be disabled.
+		 * The control thread will re-enable it after it has
+		 * checked the root hub status.
X 		 */
+	} else {
+		/* check the root hub status anyways. Some controllers
+		 * might not generate the interrupt properly. (?) */
+		ohci_root_hub_events(ohci);
X 	}
X 
-	/* Re-enable done queue interrupts and reset the donehead */
-	hcca->donehead = 0;
-	writel(OHCI_INTR_WDH, ®s->intrenable);
-	
+	/* Check those "other" pesky bits */
+	if (context & (OHCI_INTR_FNO)) {
+		writel(OHCI_INTR_FNO, ®s->intrstatus);
+		context &= ~OHCI_INTR_FNO;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_SO) {
+		writel(OHCI_INTR_SO, ®s->intrstatus);
+		context &= ~OHCI_INTR_SO;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_RD) {
+		writel(OHCI_INTR_RD, ®s->intrstatus);
+		context &= ~OHCI_INTR_RD;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_UE) {
+		/* FIXME: need to have the control thread reset the
+		 * controller now and keep a count of unrecoverable
+		 * errors.  If there are too many, it should just shut
+		 * the broken controller down entirely. */
+		writel(OHCI_INTR_UE, ®s->intrstatus);
+		context &= ~OHCI_INTR_UE;  /* mark this as checked */
+	}
+	if (context & OHCI_INTR_OC) {
+		writel(OHCI_INTR_OC, ®s->intrstatus);
+		context &= ~OHCI_INTR_OC;  /* mark this as checked */
+	}
+
+	/* Mask out any remaining unprocessed interrupts so we don't
+	 * get any more of them. */
+	if (context & ~OHCI_INTR_MIE) {
+		writel(context, ®s->intrdisable);
+	}
+
+	/* Re-enable HC interrupts */
+	writel(OHCI_INTR_MIE, ®s->intrenable);
+
X } /* ohci_interrupt() */
X 
X 
@@ -682,6 +1179,10 @@
X 	struct ohci_device *dev;
X 	struct usb_device *usb;
X 
+#if 0
+	printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base);
+#endif
+
X 	ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
X 	if (!ohci)
X 		return NULL;
@@ -703,6 +1204,8 @@
X 	bus->op = &ohci_device_operations;
X 
X 	/*
+	 * Allocate the USB device structure and root hub.
+	 *
X 	 * Here we allocate our own root hub and TDs as well as the
X 	 * OHCI host controller communications area.  The HCCA is just
X 	 * a nice pool of memory with pointers to endpoint descriptors
@@ -717,17 +1220,22 @@
X 	usb->bus = bus;
X 
X 	/* Initialize the root hub */
-	memset(dev, 0, sizeof(*dev));
X 	dev->ohci = ohci;    /* link back to the controller */
X 
X 	/*
-	 * Allocate the Host Controller Communications Area
+	 * Allocate the Host Controller Communications Area on a 256
+	 * byte boundary.  XXX take the easy way out and just grab a
+	 * page as that's guaranteed to have a nice boundary.
X 	 */
-	dev->hcca = (struct ohci_hcca *) kmalloc(sizeof(*dev->hcca), GFP_KERNEL);
+	dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
X 
X 	/* Tell the controller where the HCCA is */
X 	writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
X 
+#if 0
+	printk(KERN_DEBUG "usb-ohci: HCCA allocated at %p (bus %p)\n", dev->hcca, (void*)virt_to_bus(dev->hcca));
+#endif
+
X 	/* Get the number of ports on the root hub */
X 	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
X 	if (usb->maxchild > MAX_ROOT_PORTS) {
@@ -740,11 +1248,6 @@
X 	}
X 	printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
X 
-	printk("alloc_ohci() controller\n");
-	show_ohci_status(ohci);
-	printk("alloc_ohci() root_hub device\n");
-	show_ohci_device(dev);
-
X 	/*
X 	 * Initialize the ED polling "tree" (for simplicity's sake in
X 	 * this driver many nodes in the tree will be identical)
@@ -759,11 +1262,9 @@
X 	 * Initialize the polling table to call interrupts at the
X 	 * intended intervals.
X 	 */
-	for (i = 0; i < NUM_INTS; i++) {
-		if (i == 0)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_32]);
-		else if (i & 1)
+	dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]);
+	for (i = 1; i < NUM_INTS; i++) {
+		if (i & 1)
X 			dev->hcca->int_table[i] =
X 				virt_to_bus(&dev->ed[ED_INT_16]);
X 		else if (i & 2)
@@ -782,9 +1283,23 @@
X 
X 	/*
X 	 * Tell the controller where the control and bulk lists are
+	 * The lists start out empty.
X 	 */
+	writel(0, &ohci->regs->ed_controlhead);
+	writel(0, &ohci->regs->ed_bulkhead);
+	/*
X 	writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
X 	writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
+	*/
+
+#if 0
+	printk(KERN_DEBUG "alloc_ohci(): controller\n");
+	show_ohci_status(ohci);
+#endif
+
+#if 0
+	printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci);
+#endif
X 
X 	return ohci;
X } /* alloc_ohci() */
@@ -795,16 +1310,25 @@
X  */
X static void release_ohci(struct ohci *ohci)
X {
+	printk(KERN_DEBUG "entering release_ohci %p\n", ohci);
+
+#ifdef OHCI_TIMER
+	/* stop our timer */
+	del_timer(&ohci_timer);
+#endif
X 	if (ohci->irq >= 0) {
X 		free_irq(ohci->irq, ohci);
X 		ohci->irq = -1;
X 	}
X 
+	/* stop all OHCI interrupts */
+	writel(~0x0, &ohci->regs->intrdisable);
+
X 	if (ohci->root_hub) {
X 		/* ensure that HC is stopped before releasing the HCCA */
X 		writel(OHCI_USB_SUSPEND, &ohci->regs->control);
-		free_pages((unsigned int) ohci->root_hub->hcca, 1);
-		free_pages((unsigned int) ohci->root_hub, 1);
+		free_page((unsigned long) ohci->root_hub->hcca);
+		kfree(ohci->root_hub);
X 		ohci->root_hub->hcca = NULL;
X 		ohci->root_hub = NULL;
X 	}
@@ -812,20 +1336,26 @@
X 	/* unmap the IO address space */
X 	iounmap(ohci->regs);
X 
+	kfree(ohci);
+
+	MOD_DEC_USE_COUNT;
+
X 	/* If the ohci itself were dynamic we'd free it here */
X 
+	printk(KERN_DEBUG "usb-ohci: HC resources released.\n");
X } /* release_ohci() */
X 
+
X /*
X  * USB OHCI control thread
X  */
X static int ohci_control_thread(void * __ohci)
X {
X 	struct ohci *ohci = (struct ohci *)__ohci;
-	
+
X 	/*
X 	 * I'm unfamiliar with the SMP kernel locking.. where should
-	 * this be released?  -greg
+	 * this be released and what does it do?  -greg
X 	 */
X 	lock_kernel();
X 
@@ -833,7 +1363,7 @@
X 	 * This thread doesn't need any user-level access,
X 	 * so get rid of all of our resources..
X 	 */
-	printk("ohci_control_thread at %p\n", &ohci_control_thread);
+	printk("ohci_control_thread code at %p\n", &ohci_control_thread);
X 	exit_mm(current);
X 	exit_files(current);
X 	exit_fs(current);
@@ -843,23 +1373,64 @@
X 	/*
X 	 * Damn the torpedoes, full speed ahead
X 	 */
-	start_hc(ohci);
-	do {
+	if (start_hc(ohci) < 0) {
+		printk("usb-ohci: failed to start the controller\n");
+		release_ohci(ohci);
+		printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+		return 0;
+	}
+
+	for(;;) {
+		siginfo_t info;
+		int unsigned long signr;
+
+		wait_ms(200);
+
+		/* check the root hub configuration for changes. */
+		ohci_check_configuration(ohci);
+
+		/* re-enable root hub status change interrupts. */
+#if 0
+		writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
+#endif
+
+		printk(KERN_DEBUG "ohci-control thread sleeping\n");
X 		interruptible_sleep_on(&ohci_configure);
X #ifdef CONFIG_APM
X 		if (apm_resume) {
X 			apm_resume = 0;
-			start_hc(ohci);
+			if (start_hc(ohci) < 0)
+				break;
X 			continue;
X 		}
X #endif
-		ohci_check_configuration(ohci);
-	} while (!signal_pending(current));
X 
-	reset_hc(ohci);
+		/*
+		 * If we were woken up by a signal, see if its useful,
+		 * otherwise exit.
+		 */
+		if (signal_pending(current)) {
+			/* sending SIGUSR1 makes us print out some info */
+			spin_lock_irq(¤t->sigmask_lock);
+			signr = dequeue_signal(¤t->blocked, &info);
+			spin_unlock_irq(¤t->sigmask_lock);
+
+			if(signr == SIGUSR1) {
+				/* FIXME: have it do a full ed/td queue dump */
+				printk(KERN_DEBUG "OHCI status dump:\n");
+				show_ohci_status(ohci);
+			} else {
+				/* unknown signal, exit the thread */
+				break;
+			}
+		}
+	} /* for (;;) */
X 
+	reset_hc(ohci);
X 	release_ohci(ohci);
-	MOD_DEC_USE_COUNT;
+
+	printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
+
X 	return 0;
X } /* ohci_control_thread() */
X 
@@ -892,10 +1463,28 @@
X 		break;
X 	}
X 	return 0;
-}
+} /* handle_apm_event() */
+#endif
+
+
+#ifdef OHCI_TIMER
+/*
+ * Inspired by Iñaky's driver.  This function is a timer routine that
+ * is called OHCI_TIMER_FREQ times per second.  It polls the root hub
+ * for status changes as on my system things are acting a bit odd at
+ * the moment..
+ */
+static void ohci_timer_func (unsigned long ohci_ptr)
+{
+	struct ohci *ohci = (struct ohci*)ohci_ptr;
+
+	ohci_root_hub_events(ohci);
+
+	/* press the snooze button... */
+	mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ));
+} /* ohci_timer_func() */
X #endif
X 
-/* ... */
X 
X /*
X  * Increment the module usage count, start the control thread and
@@ -906,32 +1495,50 @@
X 	int retval;
X 	struct ohci *ohci;
X 
+#if 0
+	printk(KERN_DEBUG "entering found_ohci %d %p\n", irq, mem_base);
+#endif
+
X 	/* Allocate the running OHCI structures */
X 	ohci = alloc_ohci(mem_base);
-	if (!ohci)
+	if (!ohci) {
X 		return -ENOMEM;
+	}
X 
-	printk("usb-ohci: alloc_ohci() = %p\n", ohci);
-
-	reset_hc(ohci);
+#ifdef OHCI_TIMER
+	init_timer(&ohci_timer);
+	ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ);
+	ohci_timer.data = (unsigned long)ohci;
+	ohci_timer.function = ohci_timer_func;
+#endif
X 
X 	retval = -EBUSY;
X 	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
X 		int pid;
X 
-		MOD_INC_USE_COUNT;
X 		ohci->irq = irq;
X 
+#if 0
+		printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n");
+#endif
+
X 		/* fork off the handler */
X 		pid = kernel_thread(ohci_control_thread, ohci,
X 				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-		if (pid >= 0)
+		if (pid >= 0) {
X 			return 0;
+		}
X 
-		MOD_DEC_USE_COUNT;
X 		retval = pid;
+	} else {
+		printk("usb-ohci: Couldn't allocate interrupt %d\n", irq);
X 	}
X 	release_ohci(ohci);
+
+#if 0
+	printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base);
+#endif
+
X 	return retval;
X } /* found_ohci() */
X 
@@ -941,35 +1548,44 @@
X  */
X static int init_ohci(struct pci_dev *dev)
X {
-	unsigned int mem_base = dev->base_address[0];
+	unsigned long mem_base = dev->base_address[0];
X 	
-	printk("usb-ohci: mem_base is %p\n", (void*)mem_base);
-
X 	/* If its OHCI, its memory */
X 	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
X 		return -ENODEV;
X 
X 	/* Get the memory address and map it for IO */
X 	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	/* no interrupt won't work... */
+	if (dev->irq == 0) {
+		printk("usb-ohci: no irq assigned? check your BIOS settings.\n");
+		return -ENODEV;
+	}
+
X 	/* 
X 	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
X 	 * as the Alpha) [?]  What should I use instead...
X 	 *
X 	 * The iounmap() is done on in release_ohci.
X 	 */
-	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+	mem_base = (unsigned long) ioremap_nocache(mem_base, 4096);
X 
X 	if (!mem_base) {
X 		printk("Error mapping OHCI memory\n");
X 		return -EFAULT;
X 	}
+        MOD_INC_USE_COUNT;
X 
-	return found_ohci(dev->irq, (void *) mem_base);
-} /* init_ohci() */
+	if (found_ohci(dev->irq, (void *) mem_base) < 0) {
+		MOD_DEC_USE_COUNT;
+		return -1;
+	}
X 
+	return 0;
+} /* init_ohci() */
X 
X #ifdef MODULE
-
X /*
X  *  Clean up when unloading the module
X  */
@@ -978,6 +1594,10 @@
X #ifdef CONFIG_APM
X 	apm_unregister_callback(&handle_apm_event);
X #endif
+#ifdef CONFIG_USB_MOUSE
+	usb_mouse_cleanup();
+#endif
+	printk("usb-ohci: module unloaded\n");
X }
X 
X #define ohci_init init_module
@@ -1005,6 +1625,8 @@
X 		return -ENODEV;
X 	}
X 
+	printk("OHCI USB Driver loading\n");
+
X 	retval = -ENODEV;
X 	for (;;) {
X 		/* Find an OHCI USB controller */
@@ -1024,9 +1646,16 @@
X 
X 		/* TODO check module params here to determine what to load */
X 
-/*		usb_mouse_init(); */
-/*		usb_kbd_init();
-		hub_init();	*/
+#ifdef CONFIG_USB_MOUSE
+		usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD		
+		usb_kbd_init();
+#endif		
+		hub_init();
+#ifdef CONFIG_USB_AUDIO		
+		usb_audio_init();
+#endif		
X #ifdef CONFIG_APM
X 		apm_register_callback(&handle_apm_event);
X #endif
@@ -1034,7 +1663,7 @@
X 		return 0; /* no error */
X 	}
X 	return retval;
-} /* init_module() */
+} /* ohci_init */
X 
X /* vim:sw=8
X  */
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.2.7/linux/drivers/usb/ohci.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/ohci.h	Tue May 11 10:04:03 1999
@@ -6,7 +6,7 @@
X  *
X  * (C) Copyright 1999 Gregory P. Smith <gr...@electricrain.com>
X  *
- * $Id: ohci.h,v 1.6 1999/04/24 22:50:06 greg Exp $
+ * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $
X  */
X 
X #include <linux/list.h>
@@ -14,50 +14,65 @@
X 
X #include "usb.h"
X 
+struct ohci_ed;
+
X /*
X  * Each TD must be aligned on a 16-byte boundary.  From the OHCI v1.0 spec
X  * it does not state that TDs must be contiguious in memory (due to the
X  * use of the next_td field).  This gives us extra room at the end of a
X  * TD for our own driver specific data.
X  *
- * This structure's size must be a multiple of 16 bytes.
+ * This structure's size must be a multiple of 16 bytes. ?? no way, I
+ * don't see why.  Alignment should be all that matters.
X  */
X struct ohci_td {
X     	/* OHCI Hardware fields */
-    	__u32 info;
-	__u32 cur_buf;		/* Current Buffer Pointer */
-	__u32 next_td;		/* Next TD Pointer */
-	__u32 buf_end;		/* Memory Buffer End Pointer */
+    	__u32 info;		/* TD status & type flags */
+	__u32 cur_buf;		/* Current Buffer Pointer (bus address) */
+	__u32 next_td;		/* Next TD Pointer (bus address) */
+	__u32 buf_end;		/* Memory Buffer End Pointer (bus address) */
X 
X 	/* Driver specific fields */
-	struct list_head irq_list;	/* Active interrupt list */
+	struct ohci_ed *ed;		/* address of the ED this TD is on */
+	struct ohci_td *next_dl_td;	/* used during donelist processing */
+	void *data;			/* virt. address of the the buffer */
X 	usb_device_irq completed;	/* Completion handler routine */
-	void *data;	/* XXX ? */
-	void *dev_id;	/* XXX ? */
-	__u32 ed_bus;			/* bus address of original ED */
-} __attribute((aligned(32)));
+	int allocated;			/* boolean: is this TD allocated? */
+
+	/* User or Device class driver specific fields */
+	void *dev_id;	/* user defined pointer passed to irq handler */
+} __attribute((aligned(16)));
X 
X #define OHCI_TD_ROUND	(1 << 18)	/* buffer rounding bit */
-#define OHCI_TD_D	(3 << 11)	/* direction of xfer: */
-#define OHCI_TD_D_IN	(2 << 11)
-#define OHCI_TD_D_OUT	(1 << 11)
-#define OHCI_TD_D_SETUP (0)
+#define OHCI_TD_D	(3 << 19)	/* direction of xfer: */
+#define OHCI_TD_D_IN	(2 << 19)
+#define OHCI_TD_D_OUT	(1 << 19)
+#define OHCI_TD_D_SETUP (0 << 19)
X #define td_set_dir_in(d)	((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT )
X #define td_set_dir_out(d)	((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
X #define OHCI_TD_IOC_DELAY (7 << 21)	/* frame delay allowed before int. */
X #define OHCI_TD_IOC_OFF	(OHCI_TD_IOC_DELAY)	/* no interrupt on complete */
X #define OHCI_TD_DT	(3 << 24)	/* data toggle bits */
+#define TOGGLE_AUTO	(0 << 24)	/* automatic (from the ED) */
+#define TOGGLE_DATA0	(2 << 24)	/* force Data0 */
+#define TOGGLE_DATA1	(3 << 24)	/* force Data1 */
X #define td_force_toggle(b)	(((b) | 2) << 24)
X #define OHCI_TD_ERRCNT	(3 << 26)	/* error count */
-#define td_errorcount(td)	(((td) >> 26) & 3)
+#define td_errorcount(td)	(((td).info >> 26) & 3)
X #define OHCI_TD_CC	(0xf << 28)	/* condition code */
+#define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf)
X #define OHCI_TD_CC_NEW	(OHCI_TD_CC)	/* set this on all unaccessed TDs! */
-#define td_cc_notaccessed(td)	((td >> 29) == 7)
-#define td_cc_accessed(td)	((td >> 29) != 7)
-#define td_cc_noerror(td)	(((td) & OHCI_TD_CC) == 0)
+#define td_cc_notaccessed(td)	(((td).info >> 29) == 7)
+#define td_cc_accessed(td)	(((td).info >> 29) != 7)
+#define td_cc_noerror(td)	((((td).info) & OHCI_TD_CC) == 0)
X #define td_active(td)	(!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
X #define td_done(td)	(td_cc_noerror((td)) || (td_errorcount((td)) == 3))
X 
+#define td_allocated(td)	((td).allocated)
+#define allocate_td(td)		((td)->allocated = 1)
+#define ohci_free_td(td)	((td)->allocated = 0)
+
+
X /*
X  * The endpoint descriptors also requires 16-byte alignment
X  */
@@ -65,10 +80,16 @@
X 	/* OHCI hardware fields */
X 	__u32 status;
X 	__u32 tail_td;	/* TD Queue tail pointer */
-	__u32 head_td;	/* TD Queue head pointer */
+	__u32 _head_td;	/* TD Queue head pointer, toggle carry & halted bits */
X 	__u32 next_ed;	/* Next ED */
X } __attribute((aligned(16)));
X 
+/* get the head_td */
+#define ed_head_td(ed)	((ed)->_head_td & 0xfffffff0)
+
+/* save the carry flag while setting the head_td */
+#define set_ed_head_td(ed, td)	((ed)->_head_td = (td) | ((ed)->_head_td & 3))
+
X #define OHCI_ED_SKIP	(1 << 14)
X #define OHCI_ED_MPS	(0x7ff << 16)
X /* FIXME: should cap at the USB max packet size [0x4ff] */
@@ -90,10 +111,10 @@
X 
X /* NOTE: bits 27-31 of the status dword are reserved for the driver */
X /*
- * We'll use this status flag for the non-predefined EDs to mark if
- * they're in use or not.
+ * We'll use this status flag for to mark if an ED is in use by the
+ * driver or not.  If the bit is set, it is used.
X  *
- * FIXME: unimplemented (needed?)
+ * FIXME: implement this!
X  */
X #define ED_USED	(1 << 31)
X 
@@ -174,8 +195,8 @@
X 
X /*
X  * Given a period p in ms, convert it to the closest endpoint
- * interrupt frequency; rounding down.  I'm sure many feel that this
- * is a gross macro.  Feel free to toss it for actual code.
+ * interrupt frequency; rounding down.  This is a gross macro.
+ * Feel free to toss it for actual code. (gasp!)
X  */
X #define ms_to_ed_int(p) \
X 	((p >= 32) ? ED_INT_32 : \
@@ -257,6 +278,15 @@
X #define PORT_OCIC	(1 << 19)	/* port over current indicator chg */
X #define PORT_PRSC	(1 << 20)	/* port reset status change */
X 
+/*
+ * Root Hub status register masks
+ */
+#define OHCI_ROOT_LPS	(1)		/* turn off root hub ports power */
+#define OHCI_ROOT_OCI	(1 << 1)	/* Overcurrent Indicator */
+#define OHCI_ROOT_DRWE	(1 << 15)	/* Device remote wakeup enable */
+#define OHCI_ROOT_LPSC	(1 << 16)	/* turn on root hub ports power */
+#define OHCI_ROOT_OCIC	(1 << 17)	/* Overcurrent indicator change */
+#define OHCI_ROOT_CRWE	(1 << 31)	/* Clear RemoteWakeupEnable */
X 
X /*
X  * Interrupt register masks
@@ -276,6 +306,19 @@
X  */
X #define OHCI_USB_OPER		(2 << 6)
X #define OHCI_USB_SUSPEND	(3 << 6)
+#define OHCI_USB_PLE		(1 << 2)  /* Periodic (interrupt) list enable */
+#define OHCI_USB_IE		(1 << 3)  /* Isochronous list enable */
+#define OHCI_USB_CLE		(1 << 4)  /* Control list enable */
+#define OHCI_USB_BLE		(1 << 5)  /* Bulk list enable */
+
+/*
+ * Command status register masks
+ */
+#define OHCI_CMDSTAT_HCR	(1)
+#define OHCI_CMDSTAT_CLF	(1 << 1)
+#define OHCI_CMDSTAT_BLF	(1 << 2)
+#define OHCI_CMDSTAT_OCR	(1 << 3)
+#define OHCI_CMDSTAT_SOC	(3 << 16)
X 
X /*
X  * This is the full ohci controller description
@@ -291,10 +334,15 @@
X 	struct list_head interrupt_list;	/* List of interrupt active TDs for this OHCI */
X };
X 
+#define OHCI_TIMER
+#define OHCI_TIMER_FREQ	(1)		/* frequency of OHCI status checks */
+
X /* Debugging code */
-void show_ed(struct ohci_ed *ed);
-void show_td(struct ohci_td *td);
-void show_status(struct ohci *ohci);
+void show_ohci_ed(struct ohci_ed *ed);
+void show_ohci_td(struct ohci_td *td);
+void show_ohci_status(struct ohci *ohci);
+void show_ohci_device(struct ohci_device *dev);
+void show_ohci_hcca(struct ohci_hcca *hcca);
X 
X #endif
X /* vim:sw=8
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/restart linux/drivers/usb/restart
--- v2.2.7/linux/drivers/usb/restart	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/restart	Tue May 11 10:04:03 1999
@@ -11,25 +11,28 @@
X #  fi
X #fi
X 
-UPID=`ps aux | grep uhci-control | grep -v grep | awk '{print $2}'`
+UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
X if test "$UPID"; then
X   echo "$ME: killing $UPID"
X   kill $UPID
X fi
X 
-UMOD=`lsmod | grep '^usb-uhci' | grep -v grep`
+UMOD=`lsmod | grep '^usb-ohci' | grep -v grep`
X if test "$UMOD"; then
-  echo "$ME: removing usb-uhci.o"
+  echo "$ME: removing usb-ohci.o"
X   sleep 1
-  if ! rmmod usb-uhci; then
-    echo "$ME: cannot remove usb-uhci.o"
+  if ! rmmod usb-ohci; then
+    echo "$ME: cannot remove usb-ohci.o"
X     exit 1
X   fi
X fi
X 
X dmesg -c > /dev/null
X 
-echo "$ME: starting usb-uhci.o"
-insmod -m usb-uhci.o > usb-uhci.map
-#echo "$ME: starting bp-mouse.o"
-#insmod -m bp-mouse.o > bp-mouse.map
+echo "$ME: starting usb-ohci.o"
+insmod -m usb-ohci.o > usb-ohci.map
+
+sleep 1
+UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
+if test "$UPID"; then echo "$ME: ohci-control is pid $UPID" ; fi
+
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/stopusb linux/drivers/usb/stopusb
--- v2.2.7/linux/drivers/usb/stopusb	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/stopusb	Tue May 11 10:04:03 1999
@@ -1,8 +1,7 @@
X #!/bin/sh
X 
-killall uhci-control
-killall khubd
+killall ohci-control
X 
-sleep 1
+sleep 2
X 
-rmmod usb-uhci
+rmmod usb-ohci
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.2.7/linux/drivers/usb/uhci.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/uhci.c	Fri Apr 30 08:20:53 1999
@@ -47,9 +47,6 @@
X 
X #define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0)
X 
-int usb_mouse_init(void);
-int hub_init(void);
-
X static struct wait_queue *uhci_configure = NULL;
X 
X /*
@@ -515,6 +512,7 @@
X 
X 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
X 	if (!dev) {
+		usb_destroy_configuration(usb_dev);
X 		kfree(usb_dev);
X 		return NULL;
X 	}
@@ -573,6 +571,7 @@
X 	}
X 
X 	kfree(dev);
+	usb_destroy_configuration(usb_dev);
X 	kfree(usb_dev);
X 
X 	return 0;
@@ -995,6 +994,8 @@
X 	kfree(uhci);
X }
X 
+void cleanup_drivers(void);
+
X static int uhci_control_thread(void * __uhci)
X {
X 	struct uhci *uhci = (struct uhci *)__uhci;
@@ -1052,6 +1053,8 @@
X 			usb_disconnect(uhci->root_hub->usb->children + i);
X #endif
X 
+	cleanup_drivers();
+
X 	reset_hc(uhci);
X 	release_region(uhci->io_addr, 32);
X 
@@ -1199,4 +1202,12 @@
X 		return 0;
X 	}
X 	return retval;
+}
+
+void cleanup_drivers(void)
+{
+	hub_cleanup();
+#ifdef CONFIG_USB_MOUSE
+	usb_mouse_cleanup();
+#endif
X }
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.2.7/linux/drivers/usb/usb.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/usb.c	Fri May  7 15:16:04 1999
@@ -213,6 +213,15 @@
X 		return -1;
X 	}
X 
+	interface->endpoint = (struct usb_endpoint_descriptor *)
+		kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
+	if(interface->endpoint==NULL)
+	{
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;	
+	}
+	memset(interface->endpoint, 0, interface->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
+	
X 	for (i = 0; i < interface->bNumEndpoints; i++) {
X //		if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) {
X //			parsed += 9;	/* skip over the HID descriptor for now */
@@ -242,8 +251,18 @@
X 	{
X 		printk(KERN_WARNING "usb: too many interfaces.\n");
X 		return -1;
+
X 	}
X 
+	config->interface = (struct usb_interface_descriptor *)
+		kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
+	if(config->interface==NULL)
+	{
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;	
+	}
+	memset(config->interface, 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor));
+	
X 	for (i = 0; i < config->bNumInterfaces; i++) {
X 		int retval = usb_parse_interface(dev, config->interface + i, ptr + parsed, len);
X 		if (retval < 0)
@@ -266,6 +285,14 @@
X 		return -1;
X 	}
X 
+	dev->config = (struct usb_config_descriptor *)
+		kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL);
+	if(dev->config==NULL)
+	{
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;	
+	}
+	memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor));
X 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
X 		int retval = usb_parse_config(dev, dev->config + i, ptr, bytes);
X 		if (retval < 0)
@@ -276,6 +303,31 @@
X 	return 0;
X }
X 
+void usb_destroy_configuration(struct usb_device *dev)
+{
+	int c, i;
+	struct usb_config_descriptor *cf;
+	struct usb_interface_descriptor *ifp;
+	
+	if(dev->config==NULL)
+		return;
+	for(c=0;c<dev->descriptor.bNumConfigurations;c++)
+	{
+		cf=&dev->config[c];
+		if(cf->interface==NULL)
+			break;
+		for(i=0;i<cf->bNumInterfaces;i++)
+		{
+			ifp=&cf->interface[i];
+			if(ifp->endpoint==NULL)
+				break;
+			kfree(ifp->endpoint);
+		}
+		kfree(cf->interface);
+	}
+	kfree(dev->config);
+}
+			
X void usb_init_root_hub(struct usb_device *dev)
X {
X 	dev->devnum = -1;
@@ -517,24 +569,29 @@
X 
X int usb_get_configuration(struct usb_device *dev)
X {
-	unsigned int size;
+	unsigned int cfgno,size;
X 	unsigned char buffer[400];
-
-	/* Get the first 8 bytes - guaranteed */
-	if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, 8))
-		return -1;
-
-	/* Get the full buffer */
-	size = *(unsigned short *)(buffer+2);
-	if (size > sizeof(buffer))
-	{
-		printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
-		size = sizeof(buffer);
+	unsigned char * bufptr;
+	
+	bufptr=buffer;
+        for (cfgno=0;cfgno<dev->descriptor.bNumConfigurations;cfgno++) {
+  		/* Get the first 8 bytes - guaranteed */
+	  	if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8))
+	    		return -1;
+
+  	  	/* Get the full buffer */
+	  	size = *(unsigned short *)(bufptr+2);
+	  	if (bufptr+size > buffer+sizeof(buffer))
+	  	{
+			printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
+			size = buffer+sizeof(buffer)-bufptr;
+		}
+		if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size))
+			return -1;
+			
+		/* Prepare for next configuration */
+		bufptr+=size;
X 	}
-
-	if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, size))
-		return -1;
-
X 	return usb_parse_configuration(dev, buffer, size);
X }
X 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.2.7/linux/drivers/usb/usb.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/usb.h	Tue May 11 10:04:03 1999
@@ -1,6 +1,7 @@
X #ifndef __LINUX_USB_H
X #define __LINUX_USB_H
X 
+#include <linux/config.h>
X #include <linux/types.h>
X #include <linux/list.h>
X #include <linux/sched.h>
@@ -8,7 +9,7 @@
X static __inline__ void wait_ms(unsigned int ms)
X {
X         current->state = TASK_UNINTERRUPTIBLE;
-        schedule_timeout(1 + ms / 10);
+        schedule_timeout(1 + ms * HZ / 1000);
X }
X 
X 
@@ -99,17 +100,11 @@
X  *
X  * USB device information
X  *
- * Make this MUCH dynamic, right now
- * it contains enough information for
- * a USB floppy controller, and nothing
- * else.
- *
- * I'm not proud. I just want this dang
- * thing to start working.
X  */
-#define USB_MAXCONFIG		2
-#define USB_MAXINTERFACES	8
-#define USB_MAXENDPOINTS	4
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 24'
echo 'File patch-2.2.8 is continued in part 25'
echo 25 > _shar_seq_.tmp
#!/bin/sh
# this is part 25 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 25; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+
+#define USB_MAXCONFIG		8
+#define USB_MAXINTERFACES	32
+#define USB_MAXENDPOINTS	32
X 
X struct usb_device_descriptor {
X 	__u8  bLength;
@@ -136,6 +131,7 @@
X 	__u8  bmAttributes;
X 	__u16 wMaxPacketSize;
X 	__u8  bInterval;
+	void  *audio;
X };
X 
X /* Interface descriptor */
@@ -150,7 +146,8 @@
X 	__u8  bInterfaceProtocol;
X 	__u8  iInterface;
X 
-	struct usb_endpoint_descriptor endpoint[USB_MAXENDPOINTS];
+	struct usb_endpoint_descriptor *endpoint;
+	void  *audio;
X };
X 
X /* Configuration descriptor information.. */
@@ -164,7 +161,7 @@
X 	__u8  bmAttributes;
X 	__u8  MaxPower;
X 
-	struct usb_interface_descriptor interface[USB_MAXINTERFACES];
+	struct usb_interface_descriptor *interface;
X };
X 
X /* String descriptor */
@@ -197,6 +194,14 @@
X 
X /*
X  * Pointer to a device endpoint interrupt function -greg
+ *   Parameters:
+ *     int status - This needs to be defined.  Right now each HCD
+ *         passes different transfer status bits back.  Don't use it
+ *         until we come up with a common meaning.
+ *     void *buffer - This is a pointer to the data used in this
+ *         USB transfer.
+ *     void *dev_id - This is a user defined pointer set when the IRQ
+ *         is requested that is passed back.
X  */
X typedef int (*usb_device_irq)(int, void *, void *);
X 
@@ -228,7 +233,7 @@
X 	struct usb_bus *bus;					/* Bus we're apart of */
X 	struct usb_driver *driver;				/* Driver */
X 	struct usb_device_descriptor descriptor;		/* Descriptor */
-	struct usb_config_descriptor config[USB_MAXCONFIG];	/* All of the configs */
+	struct usb_config_descriptor *config;			/* All of the configs */
X 	struct usb_device *parent;
X   
X 	/*
@@ -363,8 +368,8 @@
X void usb_audio_interface(struct usb_interface_descriptor *, u8 *);
X void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *);
X #else
-extern inline void usb_audio_interface(struct usb_interface_descriptor *, u8 *) {}
-extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *) {}
+extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {}
+extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {}
X #endif
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
--- v2.2.7/linux/drivers/video/matroxfb.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/video/matroxfb.c	Thu Apr 29 12:53:48 1999
@@ -57,6 +57,9 @@
X  *               "H. Peter Arvin" <h...@transmeta.com>
X  *                     Ideas
X  *
+ *               "Cort Dougan" <co...@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
X  * (following author is not in any relation with this code, but his code
X  *  is included in this driver)
X  *
@@ -187,14 +190,8 @@
X #if defined(__m68k__)
X #define MAP_BUSTOVIRT
X #else
-#if defined(CONFIG_PPC) && defined(CONFIG_PREP) && defined(_ISA_MEM_BASE)
-/* do not tell me that PPC is not broken... if ioremap() oops with
-   invalid value written to msr... */
-#define MAP_ISAMEMBASE
-#else
X #define MAP_IOREMAP
X #endif
-#endif
X 
X #ifdef DEBUG
X #define dprintk(X...)	printk(X)
@@ -354,11 +351,7 @@
X #ifdef MAP_BUSTOVIRT
X 	virt->vaddr = bus_to_virt(phys);
X #else
-#ifdef MAP_ISAMEMBASE
-	virt->vaddr = (void*)(phys + _ISA_MEM_BASE);
-#else
X #error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up"
-#endif
X #endif
X #endif
X 	return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
diff -u --recursive --new-file v2.2.7/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.2.7/linux/drivers/video/offb.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/video/offb.c	Thu Apr 29 12:53:48 1999
@@ -476,9 +476,7 @@
X 	    printk("no framebuffer address found for %s\n", dp->full_name);
X 	    return;
X 	}
-	/* needed for the gxt on the f50 -- Cort */
-	if ( dp->addrs[i].address < isa_mem_base )
-		(u_long)dp->addrs[i].address += isa_mem_base;
+
X 	address = (u_long)dp->addrs[i].address;
X 
X 	/* kludge for valkyrie */
@@ -487,6 +485,7 @@
X     }
X     offb_init_fb(dp->name, dp->full_name, width, height, depth,
X 		 pitch, address);
+    
X }
X 
X __initfunc(static void offb_init_fb(const char *name, const char *full_name,
diff -u --recursive --new-file v2.2.7/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.2.7/linux/drivers/video/vesafb.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/video/vesafb.c	Tue May 11 09:55:45 1999
@@ -21,7 +21,6 @@
X #include <linux/selection.h>
X #include <linux/ioport.h>
X #include <linux/init.h>
-#include <linux/config.h>
X 
X #include <asm/io.h>
X #include <asm/mtrr.h>
@@ -635,10 +634,8 @@
X 		video_cmap_len = 256;
X 	}
X 	request_region(0x3c0, 32, "vga+");
-#ifdef CONFIG_MTRR
X 	if (mtrr)
X 		mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1);
-#endif
X 	
X 	strcpy(fb_info.modename, "VESA VGA");
X 	fb_info.changevar = NULL;
diff -u --recursive --new-file v2.2.7/linux/fs/adfs/namei.c linux/fs/adfs/namei.c
--- v2.2.7/linux/fs/adfs/namei.c	Wed Apr 28 11:37:30 1999
+++ linux/fs/adfs/namei.c	Mon May 10 14:14:28 1999
@@ -46,7 +46,7 @@
X 	unsigned long parent_object_id, dir_object_id;
X 	int buffers, pos;
X 
-	if (!dir || !S_ISDIR(dir->i_mode))
+	if (!S_ISDIR(dir->i_mode))
X 		return 0;
X 
X 	sb = dir->i_sb;
diff -u --recursive --new-file v2.2.7/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.2.7/linux/fs/autofs/root.c	Wed Apr 28 11:37:30 1999
+++ linux/fs/autofs/root.c	Sat May  8 17:56:37 1999
@@ -168,7 +168,7 @@
X  * yet completely filled in, and revalidate has to delay such
X  * lookups..
X  */
-static int autofs_revalidate(struct dentry * dentry)
+static int autofs_revalidate(struct dentry * dentry, int flags)
X {
X 	struct inode * dir = dentry->d_parent->d_inode;
X 	struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
@@ -241,7 +241,7 @@
X 	d_add(dentry, NULL);
X 
X 	up(&dir->i_sem);
-	autofs_revalidate(dentry);
+	autofs_revalidate(dentry, 0);
X 	down(&dir->i_sem);
X 
X 	/*
diff -u --recursive --new-file v2.2.7/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.2.7/linux/fs/binfmt_aout.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/binfmt_aout.c	Mon May 10 13:01:21 1999
@@ -58,8 +58,19 @@
X  * These are the only things you should do on a core-file: use only these
X  * macros to write out all the necessary info.
X  */
-#define DUMP_WRITE(addr,nr) \
-while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump
+
+static int dump_write(struct file *file, const void *addr, int nr)
+{
+	int r;
+	down(&file->f_dentry->d_inode->i_sem);
+	r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+	up(&file->f_dentry->d_inode->i_sem);
+	return r;
+}
+
+#define DUMP_WRITE(addr, nr)	\
+	if (!dump_write(file, (void *)(addr), (nr))) \
+		goto close_coredump;
X 
X #define DUMP_SEEK(offset) \
X if (file->f_op->llseek) { \
diff -u --recursive --new-file v2.2.7/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.2.7/linux/fs/binfmt_elf.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/binfmt_elf.c	Mon May 10 13:01:21 1999
@@ -927,7 +927,11 @@
X  */
X static int dump_write(struct file *file, const void *addr, int nr)
X {
-	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+	int r;
+	down(&file->f_dentry->d_inode->i_sem);
+	r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+	up(&file->f_dentry->d_inode->i_sem);
+	return r;
X }
X 
X static int dump_seek(struct file *file, off_t off)
diff -u --recursive --new-file v2.2.7/linux/fs/buffer.c linux/fs/buffer.c
--- v2.2.7/linux/fs/buffer.c	Wed Apr 28 11:37:30 1999
+++ linux/fs/buffer.c	Tue May 11 09:55:49 1999
@@ -100,7 +100,8 @@
X 				each time we call refill */
X 		int nref_dirt; /* Dirty buffer threshold for activating bdflush
X 				  when trying to refill buffers. */
-		int dummy1;    /* unused */
+		int interval;  /* Interval (seconds) between spontaneous
+				  bdflush runs */
X 		int age_buffer;  /* Time for normal buffer to age before 
X 				    we flush it */
X 		int age_super;  /* Time for superblock to age before we 
@@ -109,10 +110,10 @@
X 		int dummy3;    /* unused */
X 	} b_un;
X 	unsigned int data[N_PARAM];
-} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
+} bdf_prm = {{40, 500, 64, 256, 5, 30*HZ, 5*HZ, 1884, 2}};
X 
X /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  1,   1*HZ,   1*HZ, 1, 1};
X int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
X 
X void wakeup_bdflush(int);
@@ -1553,7 +1554,6 @@
X  * response to dirty buffers.  Once this process is activated, we write back
X  * a limited number of buffers to the disks and then go back to sleep again.
X  */
-static struct wait_queue * bdflush_wait = NULL;
X static struct wait_queue * bdflush_done = NULL;
X struct task_struct *bdflush_tsk = 0;
X 
@@ -1561,7 +1561,7 @@
X {
X 	if (current == bdflush_tsk)
X 		return;
-	wake_up(&bdflush_wait);
+	wake_up_process(bdflush_tsk);
X 	if (wait) {
X 		run_task_queue(&tq_disk);
X 		sleep_on(&bdflush_done);
@@ -1570,82 +1570,107 @@
X 
X 
X /* 
- * Here we attempt to write back old buffers.  We also try to flush inodes 
- * and supers as well, since this function is essentially "update", and 
- * otherwise there would be no way of ensuring that these quantities ever 
- * get written back.  Ideally, we would have a timestamp on the inodes
- * and superblocks so that we could write back only the old ones as well
- */
+ * Here we attempt to write back old buffers.
+ * To prevent deadlocks for a loop device:
+ * 1) Do non-blocking writes to loop (avoids deadlock with running
+ *	out of request blocks).
+ * 2) But do a blocking write if the only dirty buffers are loop buffers
+ *	(otherwise we go into an infinite busy-loop).
+ * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
+ *	with running out of free buffers for loop's "real" device).
+*/
X 
-static int sync_old_buffers(void)
+static inline void sync_old_buffers(void)
X {
X 	int i;
-	int ndirty, nwritten;
-	int nlist;
-	int ncount;
-	struct buffer_head * bh, *next;
-
-	sync_supers(0);
-	sync_inodes(0);
-
-	ncount = 0;
+	int ndirty = 0;
+	int wrta_cmd = WRITEA;
X #ifdef DEBUG
-	for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
+	int ncount = 0, nwritten = 0;
X #endif
-	{
-		ndirty = 0;
-		nwritten = 0;
-	repeat:
+	struct buffer_head * bh, *next;
X 
-		bh = lru_list[nlist];
-		if(bh) 
-			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
-				 /* We may have stalled while waiting for I/O to complete. */
-				 if(bh->b_list != nlist) goto repeat;
-				 next = bh->b_next_free;
-				 if(!lru_list[nlist]) {
-					 printk("Dirty list empty %d\n", i);
-					 break;
-				 }
-				 
-				 /* Clean buffer on dirty list?  Refile it */
-				 if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
-					 refile_buffer(bh);
-					 continue;
-				 }
-				  
-				  /* Unlocked buffer on locked list?  Refile it */
-				  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-					  refile_buffer(bh);
-					  continue;
-				  }
-				 
-				 if (buffer_locked(bh) || !buffer_dirty(bh))
-					  continue;
-				 ndirty++;
-				 if(time_before(jiffies, bh->b_flushtime))
-					continue;
-				 nwritten++;
-				 next->b_count++;
-				 bh->b_count++;
-				 bh->b_flushtime = 0;
X #ifdef DEBUG
-				 if(nlist != BUF_DIRTY) ncount++;
+	bh = lru_list[BUF_CLEAN];
+	if(bh)
+		for(i = nr_buffers_type[BUF_CLEAN]; --i > 0; bh = next) {
+			next = bh->b_next_free;
+
+			/* Dirty/locked buffer on clean list?  Refile it */
+			if (buffer_locked(bh) || buffer_dirty(bh)) {
+				ncount++;
+				refile_buffer(bh);
+			}
+		}
X #endif
-				 ll_rw_block(WRITE, 1, &bh);
-				 bh->b_count--;
-				 next->b_count--;
-			 }
+
+	bh = lru_list[BUF_LOCKED];
+	if(bh)
+		for(i = nr_buffers_type[BUF_LOCKED]; --i > 0; bh = next) {
+			next = bh->b_next_free;
+
+			/* Unlocked buffer on locked list?  Refile it */
+			if (!buffer_locked(bh))
+				refile_buffer(bh);
+		}
+
+ restart:
+	bh = lru_list[BUF_DIRTY];
+	if(bh) 
+		for (i = nr_buffers_type[BUF_DIRTY];
+		     i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
+		     bh = next) {
+			/* We may have stalled while waiting for
+			   I/O to complete. */
+			if(bh->b_list != BUF_DIRTY)
+				goto restart;
+			next = bh->b_next_free;
+			if(!lru_list[BUF_DIRTY]) {
+				printk("Dirty list empty %d\n", i);
+				break;
+			}
+					  
+			/* Clean buffer on dirty list?  Refile it */
+			if (!buffer_dirty(bh)) {
+				refile_buffer(bh);
+				continue;
+			}
+					  
+			if (buffer_locked(bh))
+				continue;
+			/* Should we write back buffers that are
+			   shared or not??  Currently dirty buffers
+			   are not shared, so it does not matter */
+			next->b_count++;
+			bh->b_count++;
+			ndirty++;
+			bh->b_flushtime = 0;
+			if (MAJOR(bh->b_dev) == LOOP_MAJOR) {
+				ll_rw_block(wrta_cmd,1, &bh);
+				wrta_cmd = WRITEA;
+				if (buffer_dirty(bh))
+					--ndirty;
+			}
+			else
+				ll_rw_block(WRITE, 1, &bh);
+			bh->b_count--;
+			next->b_count--;
+		}
+	/* If we didn't write anything, but there are still
+	 * dirty buffers, then make the next write to a
+	 * loop device to be a blocking write.
+	 * This lets us block--which we _must_ do! */
+	if (ndirty == 0
+	    && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
+		wrta_cmd = WRITE;
+		goto restart;
X 	}
-	run_task_queue(&tq_disk);
+
X #ifdef DEBUG
X 	if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
-	printk("Wrote %d/%d buffers\n", nwritten, ndirty);
+	printk("wrote %d/%d buffers...", nwritten, ndirty);
X #endif
X 	run_task_queue(&tq_disk);
-	return 0;
X }
X 
X 
@@ -1662,10 +1687,12 @@
X 	if (!capable(CAP_SYS_ADMIN))
X 		goto out;
X 
-	if (func == 1) {
-		 error = sync_old_buffers();
-		 goto out;
-	}
+	if (func == 1)
+		/* Func 1 used to call sync_old_buffers; a user space
+		   daemon would call it periodically.  This is no
+		   longer necessary.  Returning -EPERM here makes the
+		   daemon silently exit.  */
+		goto out;
X 
X 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
X 	if (func >= 2) {
@@ -1694,27 +1721,17 @@
X 	return error;
X }
X 
-/* This is the actual bdflush daemon itself. It used to be started from
- * the syscall above, but now we launch it ourselves internally with
- * kernel_thread(...)  directly after the first thread in init/main.c */
+/* This is the actual bdflush daemon itself. It used to be started
+ * from the syscall above, but now we launch it ourselves internally
+ * with kernel_thread(...)  directly after the first thread in
+ * init/main.c.  Every so often, or when woken up by another task that
+ * needs memory, we call sync_old_buffers to partially clear the dirty list.
+ */
X 
-/* To prevent deadlocks for a loop device:
- * 1) Do non-blocking writes to loop (avoids deadlock with running
- *	out of request blocks).
- * 2) But do a blocking write if the only dirty buffers are loop buffers
- *	(otherwise we go into an infinite busy-loop).
- * 3) Quit writing loop blocks if a freelist went low (avoids deadlock
- *	with running out of free buffers for loop's "real" device).
-*/
X int bdflush(void * unused) 
X {
-	int i;
-	int ndirty;
-	int nlist;
-	int ncount;
-	struct buffer_head * bh, *next;
-	int major;
-	int wrta_cmd = WRITEA;	/* non-blocking write for LOOP */
+	long remaining = HZ * bdf_prm.b_un.interval;
+	struct task_struct *tsk = current;
X 
X 	/*
X 	 *	We have a bare-bones task_struct, and really should fill
@@ -1722,10 +1739,12 @@
X 	 *	display semi-sane things. Not real crucial though...  
X 	 */
X 
-	current->session = 1;
-	current->pgrp = 1;
-	sprintf(current->comm, "kflushd");
-	bdflush_tsk = current;
+	tsk->session = 1;
+	tsk->pgrp = 1;
+	tsk->dumpable = 0;  /* inhibit ptrace() */
+	strcpy(tsk->comm, "kflushd");
+	sigfillset(&tsk->blocked);
+	bdflush_tsk = tsk;
X 
X 	/*
X 	 *	As a kernel thread we want to tamper with system buffers
@@ -1735,93 +1754,36 @@
X 	lock_kernel();
X 		 
X 	for (;;) {
+		tsk->state = TASK_INTERRUPTIBLE;
+		remaining = schedule_timeout(remaining);
+
X #ifdef DEBUG
X 		printk("bdflush() activated...");
X #endif
-
X 		CHECK_EMERGENCY_SYNC
X 
-		ncount = 0;
-#ifdef DEBUG
-		for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-		for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
-#endif
-		 {
-			 ndirty = 0;
-		 repeat:
-
-			 bh = lru_list[nlist];
-			 if(bh) 
-				  for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
-				       bh = next) {
-					  /* We may have stalled while waiting for I/O to complete. */
-					  if(bh->b_list != nlist) goto repeat;
-					  next = bh->b_next_free;
-					  if(!lru_list[nlist]) {
-						  printk("Dirty list empty %d\n", i);
-						  break;
-					  }
-					  
-					  /* Clean buffer on dirty list?  Refile it */
-					  if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
-						  refile_buffer(bh);
-						  continue;
-					  }
-					  
-					  /* Unlocked buffer on locked list?  Refile it */
-					  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-						  refile_buffer(bh);
-						  continue;
-					  }
-					  
-					  if (buffer_locked(bh) || !buffer_dirty(bh))
-						   continue;
-					  major = MAJOR(bh->b_dev);
-					  /* Should we write back buffers that are shared or not??
-					     currently dirty buffers are not shared, so it does not matter */
-					  next->b_count++;
-					  bh->b_count++;
-					  ndirty++;
-					  bh->b_flushtime = 0;
-					  if (major == LOOP_MAJOR) {
-						  ll_rw_block(wrta_cmd,1, &bh);
-						  wrta_cmd = WRITEA;
-						  if (buffer_dirty(bh))
-							  --ndirty;
-					  }
-					  else
-					  ll_rw_block(WRITE, 1, &bh);
-#ifdef DEBUG
-					  if(nlist != BUF_DIRTY) ncount++;
-#endif
-					  bh->b_count--;
-					  next->b_count--;
-				  }
-		 }
+		if (remaining == 0) {
+			/*
+			 * Also try to flush inodes and supers, since
+			 * otherwise there would be no way of ensuring
+			 * that these quantities ever get written
+			 * back.  Ideally, we would have a timestamp
+			 * on the inodes and superblocks so that we
+			 * could write back only the old ones.
+			 */
+			sync_supers(0);
+			sync_inodes(0);
+			remaining = HZ * bdf_prm.b_un.interval;
+		}
+			
+		/* Keep flushing till there aren't very many dirty buffers */
+		do {
+			sync_old_buffers();
+		} while(nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100);
+
+		wake_up(&bdflush_done);
X #ifdef DEBUG
-		if (ncount) printk("sys_bdflush: %d dirty buffers not on dirty list\n", ncount);
X 		printk("sleeping again.\n");
X #endif
-		/* If we didn't write anything, but there are still
-		 * dirty buffers, then make the next write to a
-		 * loop device to be a blocking write.
-		 * This lets us block--which we _must_ do! */
-		if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
-			wrta_cmd = WRITE;
-			continue;
-		}
-		run_task_queue(&tq_disk);
-		wake_up(&bdflush_done);
-		
-		/* If there are still a lot of dirty buffers around, skip the sleep
-		   and flush some more */
-		if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
-			spin_lock_irq(¤t->sigmask_lock);
-			flush_signals(current);
-			spin_unlock_irq(¤t->sigmask_lock);
-
-			interruptible_sleep_on(&bdflush_wait);
-		}
X 	}
X }
diff -u --recursive --new-file v2.2.7/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.2.7/linux/fs/coda/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/coda/dir.c	Sat May  8 17:56:37 1999
@@ -44,7 +44,7 @@
X static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
X 
X /* dentry ops */
-static int coda_dentry_revalidate(struct dentry *de);
+static int coda_dentry_revalidate(struct dentry *de, int);
X static void coda_dentry_delete(struct dentry *);
X 
X /* support routines */
@@ -778,7 +778,7 @@
X }
X 
X /* called when a cache lookup succeeds */
-static int coda_dentry_revalidate(struct dentry *de)
+static int coda_dentry_revalidate(struct dentry *de, int flags)
X {
X 	int valid = 1;
X 	struct inode *inode = de->d_inode;
diff -u --recursive --new-file v2.2.7/linux/fs/devpts/root.c linux/fs/devpts/root.c
--- v2.2.7/linux/fs/devpts/root.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/devpts/root.c	Sat May  8 17:56:37 1999
@@ -18,7 +18,7 @@
X 
X static int devpts_root_readdir(struct file *,void *,filldir_t);
X static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
-static int devpts_revalidate(struct dentry *);
+static int devpts_revalidate(struct dentry *, int);
X 
X static struct file_operations devpts_root_operations = {
X 	NULL,                   /* llseek */
@@ -116,7 +116,7 @@
X  * the pty really does still exist.  Never revalidate negative dentries;
X  * for simplicity (fix later?)
X  */
-static int devpts_revalidate(struct dentry * dentry)
+static int devpts_revalidate(struct dentry * dentry, int flags)
X {
X 	struct devpts_sb_info *sbi;
X 
diff -u --recursive --new-file v2.2.7/linux/fs/dquot.c linux/fs/dquot.c
--- v2.2.7/linux/fs/dquot.c	Wed Mar 10 15:29:49 1999
+++ linux/fs/dquot.c	Fri May  7 18:04:12 1999
@@ -1268,11 +1268,11 @@
X 
X int quota_on(kdev_t dev, short type, char *path)
X {
-	struct file *filp = NULL;
-	struct dentry *dentry;
+	struct file *f;
X 	struct vfsmount *vfsmnt;
X 	struct inode *inode;
X 	struct dquot *dquot;
+	struct quota_mount_options *mnt_dquot;
X 	char *tmp;
X 	int error;
X 
@@ -1281,69 +1281,48 @@
X 		return -ENODEV;
X 
X 	if (is_enabled(vfsmnt, type))
-		return(-EBUSY);
+		return -EBUSY;
+	mnt_dquot = &vfsmnt->mnt_dquot;
X 
X 	tmp = getname(path);
X 	error = PTR_ERR(tmp);
X 	if (IS_ERR(tmp))
X 		return error;
X 
-	dentry = open_namei(tmp, O_RDWR, 0600);
+	f = filp_open(tmp, O_RDWR, 0600);
X 	putname(tmp);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
X 
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		return error;
-	inode = dentry->d_inode;
-
-	if (!S_ISREG(inode->i_mode)) {
-		dput(dentry);
-		return -EACCES;
-	}
-
-	if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0) {
-		dput(dentry);
-		return(-EINVAL);
-	}
-
-	filp = get_empty_filp();
-	if (filp != (struct file *)NULL) {
-		filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
-		filp->f_flags = O_RDWR;
-		filp->f_dentry = dentry;
-		filp->f_pos = 0;
-		filp->f_reada = 0;
-		filp->f_op = inode->i_op->default_file_ops;
-		if (filp->f_op->read || filp->f_op->write) {
-			error = get_write_access(inode);
-			if (!error) {
-				if (filp->f_op && filp->f_op->open)
-					error = filp->f_op->open(inode, filp);
-				if (!error) {
-					set_enable_flags(vfsmnt, type);
-					vfsmnt->mnt_dquot.files[type] = filp;
-
-					dquot = dqget(dev, 0, type);
-					vfsmnt->mnt_dquot.inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
-					vfsmnt->mnt_dquot.block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
-					dqput(dquot);
-
-					vfsmnt->mnt_sb->dq_op = &dquot_operations;
-					add_dquot_ref(dev, type);
-
-					return(0);
-				}
-				put_write_access(inode);
-			}
-		} else
-			error = -EIO;
-		put_filp(filp);
-	} else
-		error = -EMFILE;
-
-	dput(dentry);
-
-	return(error);
+	/* sanity checks */
+	error = -EIO;
+	if (!f->f_op->read && !f->f_op->write)
+		goto cleanup;
+	inode = f->f_dentry->d_inode;
+	error = -EACCES;
+	if (!S_ISREG(inode->i_mode))
+		goto cleanup;
+	error = -EINVAL;
+	if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
+		goto cleanup;
+
+	/* OK, there we go */
+	set_enable_flags(vfsmnt, type);
+	mnt_dquot->files[type] = f;
+
+	dquot = dqget(dev, 0, type);
+	mnt_dquot->inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
+	mnt_dquot->block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
+	dqput(dquot);
+
+	vfsmnt->mnt_sb->dq_op = &dquot_operations;
+	add_dquot_ref(dev, type);
+
+	return(0);
+
+cleanup:
+	fput(f);
+	return error;
X }
X 
X /*
@@ -1370,8 +1349,8 @@
X 		case Q_GETSTATS:
X 			break;
X 		case Q_GETQUOTA:
-			if (((type == USRQUOTA && current->uid != id) ||
-			     (type == GRPQUOTA && current->gid != id)) &&
+			if (((type == USRQUOTA && current->euid != id) ||
+			     (type == GRPQUOTA && current->egid != id)) &&
X 			    !capable(CAP_SYS_RESOURCE))
X 				goto out;
X 			break;
diff -u --recursive --new-file v2.2.7/linux/fs/exec.c linux/fs/exec.c
--- v2.2.7/linux/fs/exec.c	Tue Jan 19 11:32:52 1999
+++ linux/fs/exec.c	Thu Apr 29 22:10:12 1999
@@ -29,7 +29,6 @@
X #include <linux/a.out.h>
X #include <linux/stat.h>
X #include <linux/fcntl.h>
-#include <linux/user.h>
X #include <linux/smp_lock.h>
X #include <linux/init.h>
X 
diff -u --recursive --new-file v2.2.7/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.2.7/linux/fs/ext2/inode.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/ext2/inode.c	Tue May  4 16:27:07 1999
@@ -286,7 +286,8 @@
X 	u32 * p;
X 	struct buffer_head * result;
X 	int blocks = inode->i_sb->s_blocksize / 512;
-
+	unsigned long limit;
+	
X 	if (!bh)
X 		return NULL;
X 	if (!buffer_uptodate(bh)) {
@@ -309,13 +310,22 @@
X 		brelse (result);
X 		goto repeat;
X 	}
-	if (!create || new_block >= 
-	    (current->rlim[RLIMIT_FSIZE].rlim_cur >> 
-	     EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
+	*err = -EFBIG;
+	if (!create) {
X 		brelse (bh);
-		*err = -EFBIG;
X 		return NULL;
X 	}
+
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
+		if (new_block >= limit) {
+			brelse (bh);
+			send_sig(SIGXFSZ, current, 0);
+			return NULL;
+		}
+	}
+
X 	if (inode->u.ext2_i.i_next_alloc_block == new_block)
X 		goal = inode->u.ext2_i.i_next_alloc_goal;
X 	if (!goal) {
diff -u --recursive --new-file v2.2.7/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.2.7/linux/fs/ext2/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ext2/namei.c	Mon May 10 14:14:28 1999
@@ -74,8 +74,6 @@
X 	int block, toread, i, err;
X 
X 	*res_dir = NULL;
-	if (!dir)
-		return NULL;
X 	sb = dir->i_sb;
X 
X 	if (namelen > EXT2_NAME_LEN)
diff -u --recursive --new-file v2.2.7/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c
--- v2.2.7/linux/fs/hfs/sysdep.c	Mon Dec 28 15:00:52 1998
+++ linux/fs/hfs/sysdep.c	Sat May  8 17:56:37 1999
@@ -18,7 +18,7 @@
X #include <linux/hfs_fs_i.h>
X #include <linux/hfs_fs.h>
X 
-static int hfs_revalidate_dentry(struct dentry *);
+static int hfs_revalidate_dentry(struct dentry *, int);
X static int hfs_hash_dentry(struct dentry *, struct qstr *);
X static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
X static void hfs_dentry_iput(struct dentry *, struct inode *);
@@ -89,7 +89,7 @@
X 	iput(inode);
X }
X 
-static int hfs_revalidate_dentry(struct dentry *dentry)
+static int hfs_revalidate_dentry(struct dentry *dentry, int flags)
X {
X 	struct inode *inode = dentry->d_inode;
X 	int diff;
diff -u --recursive --new-file v2.2.7/linux/fs/inode.c linux/fs/inode.c
--- v2.2.7/linux/fs/inode.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/inode.c	Tue May  4 10:57:12 1999
@@ -522,6 +522,7 @@
X 	inode->i_nlink = 1;
X 	inode->i_writecount = 0;
X 	inode->i_size = 0;
+	inode->i_generation = 0;
X 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
X 	sema_init(&inode->i_sem, 1);
X }
diff -u --recursive --new-file v2.2.7/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.2.7/linux/fs/isofs/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/isofs/namei.c	Mon May 10 14:14:28 1999
@@ -74,7 +74,6 @@
X 	char c;
X 
X 	*ino = 0;
-	if (!dir) return NULL;
X 	
X 	if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
X   
diff -u --recursive --new-file v2.2.7/linux/fs/locks.c linux/fs/locks.c
--- v2.2.7/linux/fs/locks.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/locks.c	Tue May 11 08:52:14 1999
@@ -263,16 +263,18 @@
X 		if (waiter->fl_notify)
X 			waiter->fl_notify(waiter);
X 		wake_up(&waiter->fl_wait);
-		if (wait)
+		if (wait) {
X 			/* Let the blocked process remove waiter from the
X 			 * block list when it gets scheduled.
X 			 */
+			current->policy |= SCHED_YIELD;
X 			schedule();
-		else
+		} else {
X 			/* Remove waiter from the block list, because by the
X 			 * time it wakes up blocker won't exist any more.
X 			 */
X 			locks_delete_block(blocker, waiter);
+		}
X 	}
X 	return;
X }
diff -u --recursive --new-file v2.2.7/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.2.7/linux/fs/minix/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/minix/namei.c	Mon May 10 14:15:16 1999
@@ -45,7 +45,7 @@
X 	struct minix_dir_entry *de;
X 
X 	*res_dir = NULL;
-	if (!dir || !dir->i_sb)
+	if (!dir->i_sb)
X 		return NULL;
X 	info = &dir->i_sb->u.minix_sb;
X 	if (namelen > info->s_namelen) {
@@ -249,12 +249,6 @@
X 	struct buffer_head * bh;
X 	struct minix_dir_entry * de;
X 
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		brelse(bh);
-		return -EEXIST;
-	}
X 	inode = minix_new_inode(dir);
X 	if (!inode)
X 		return -ENOSPC;
@@ -295,12 +289,6 @@
X 	struct minix_sb_info * info;
X 
X 	info = &dir->i_sb->u.minix_sb;
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		brelse(bh);
-		return -EEXIST;
-	}
X 	if (dir->i_nlink >= info->s_link_max)
X 		return -EMLINK;
X 	inode = minix_new_inode(dir);
@@ -524,15 +512,6 @@
X 	brelse(name_block);
X 	inode->i_size = i;
X 	mark_inode_dirty(inode);
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		inode->i_nlink--;
-		mark_inode_dirty(inode);
-		iput(inode);
-		brelse(bh);
-		return -EEXIST;
-	}
X 	i = minix_add_entry(dir, dentry->d_name.name,
X 			    dentry->d_name.len, &bh, &de);
X 	if (i) {
@@ -562,12 +541,6 @@
X 	if (inode->i_nlink >= inode->i_sb->u.minix_sb.s_link_max)
X 		return -EMLINK;
X 
-	bh = minix_find_entry(dir, dentry->d_name.name,
-			      dentry->d_name.len, &de);
-	if (bh) {
-		brelse(bh);
-		return -EEXIST;
-	}
X 	error = minix_add_entry(dir, dentry->d_name.name,
X 				dentry->d_name.len, &bh, &de);
X 	if (error) {
diff -u --recursive --new-file v2.2.7/linux/fs/namei.c linux/fs/namei.c
--- v2.2.7/linux/fs/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/namei.c	Sat May  8 20:46:08 1999
@@ -23,18 +23,6 @@
X #include <asm/page.h>
X #include <asm/pgtable.h>
X 
-/*
- * The bitmask for a lookup event:
- *  - follow links at the end
- *  - require a directory
- *  - ending slashes ok even for nonexistent files
- *  - internal "there are more path compnents" flag
- */
-#define LOOKUP_FOLLOW		(1)
-#define LOOKUP_DIRECTORY	(2)
-#define LOOKUP_SLASHOK		(4)
-#define LOOKUP_CONTINUE		(8)
-
X #include <asm/namei.h>
X 
X /* This can be removed after the beta phase. */
@@ -225,12 +213,12 @@
X /*
X  * Internal lookup() using the new generic dcache.
X  */
-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
+static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
X {
X 	struct dentry * dentry = d_lookup(parent, name);
X 
X 	if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
-		if (!dentry->d_op->d_revalidate(dentry) && !d_invalidate(dentry)) {
+		if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
X 			dput(dentry);
X 			dentry = NULL;
X 		}
@@ -245,7 +233,7 @@
X  * We get the directory semaphore, and after getting that we also
X  * make sure that nobody added the entry to the dcache in the meantime..
X  */
-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
+static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
X {
X 	struct dentry * result;
X 	struct inode *dir = parent->d_inode;
@@ -258,7 +246,7 @@
X 	 * FIXME! This could use version numbering or similar to
X 	 * avoid unnecessary cache lookups.
X 	 */
-	result = cached_lookup(parent, name);
+	result = cached_lookup(parent, name, flags);
X 	if (!result) {
X 		struct dentry * dentry = d_alloc(parent, name);
X 		result = ERR_PTR(-ENOMEM);
@@ -392,9 +380,9 @@
X 		/* This does the actual lookups.. */
X 		dentry = reserved_lookup(base, &this);
X 		if (!dentry) {
-			dentry = cached_lookup(base, &this);
+			dentry = cached_lookup(base, &this, flags);
X 			if (!dentry) {
-				dentry = real_lookup(base, &this);
+				dentry = real_lookup(base, &this, flags);
X 				if (IS_ERR(dentry))
X 					break;
X 			}
diff -u --recursive --new-file v2.2.7/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.2.7/linux/fs/ncpfs/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ncpfs/dir.c	Sat May  8 17:56:37 1999
@@ -112,14 +112,14 @@
X /*
X  * Dentry operations routines
X  */
-static int ncp_lookup_validate(struct dentry *);
+static int ncp_lookup_validate(struct dentry *, int);
X static int ncp_hash_dentry(struct dentry *, struct qstr *);
X static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
X static void ncp_delete_dentry(struct dentry *);
X 
X struct dentry_operations ncp_dentry_operations =
X {
-	ncp_lookup_validate,	/* d_validate(struct dentry *) */
+	ncp_lookup_validate,	/* d_revalidate(struct dentry *, int) */
X 	ncp_hash_dentry,	/* d_hash */
X 	ncp_compare_dentry,    	/* d_compare */
X 	ncp_delete_dentry	/* d_delete(struct dentry *) */
@@ -345,7 +345,7 @@
X 
X 
X static int
-ncp_lookup_validate(struct dentry * dentry)
+ncp_lookup_validate(struct dentry * dentry, int flags)
X {
X 	struct ncp_server *server;
X 	struct inode *dir = dentry->d_parent->d_inode;
diff -u --recursive --new-file v2.2.7/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.2.7/linux/fs/nfs/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/nfs/dir.c	Sat May  8 23:18:22 1999
@@ -72,9 +72,9 @@
X 	NULL,			/* select - default */
X 	NULL,			/* ioctl - default */
X 	NULL,			/* mmap */
-	NULL,			/* no special open is needed */
+	nfs_open,		/* open */
X 	NULL,			/* flush */
-	NULL,			/* no special release code */
+ nfs_release, /* release */
X 	NULL			/* fsync */
X };
X 
@@ -364,7 +364,48 @@
X 	dentry->d_time = jiffies;
X }
X 
-#define NFS_REVALIDATE_INTERVAL (5*HZ)
+static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+	unsigned long timeout = NFS_ATTRTIMEO(inode);
+
+	/*
+	 * If it's the last lookup in a series, we use a stricter
+	 * cache consistency check by looking at the parent mtime.
+	 *
+	 * If it's been modified in the last hour, be really strict.
+	 * (This still means that we can avoid doing unnecessary
+	 * work on directories like /usr/share/bin etc which basically
+	 * never change).
+	 */
+	if (!(flags & LOOKUP_CONTINUE)) {
+		long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+		if (diff < 15*60)
+			timeout = 0;
+	}
+	
+	return time_after(jiffies,dentry->d_time + timeout);
+}
+
+/*
+ * We judge how long we want to trust negative
+ * dentries by looking at the parent inode mtime.
+ *
+ * If mtime is close to present time, we revalidate
+ * more often.
+ */
+static inline int nfs_neg_need_reval(struct dentry *dentry)
+{
+	unsigned long timeout = 30 * HZ;
+	long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+	if (diff < 5*60)
+		timeout = 1 * HZ;
+
+	return time_after(jiffies, dentry->d_time + timeout);
+}
+
X /*
X  * This is called every time the dcache has a lookup hit,
X  * and we should check whether we can really trust that
@@ -377,7 +418,7 @@
X  * we do a new lookup and verify that the dentry is still
X  * correct.
X  */
-static int nfs_lookup_revalidate(struct dentry * dentry)
+static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
X {
X 	struct dentry * parent = dentry->d_parent;
X 	struct inode * inode = dentry->d_inode;
@@ -386,11 +427,15 @@
X 	struct nfs_fattr fattr;
X 
X 	/*
-	 * If we don't have an inode, let's just assume
-	 * a 5-second "live" time for negative dentries.
+	 * If we don't have an inode, let's look at the parent
+	 * directory mtime to get a hint about how often we
+	 * should validate things..
X 	 */
-	if (!inode)
-		goto do_lookup;
+	if (!inode) {
+		if (nfs_neg_need_reval(dentry))
+			goto out_bad;
+		goto out_valid;
+	}
X 
X 	if (is_bad_inode(inode)) {
X 		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
@@ -398,27 +443,17 @@
X 		goto out_bad;
X 	}
X 
-	if (_nfs_revalidate_inode(NFS_DSERVER(dentry), dentry))
-		goto out_bad;
-
-	if (time_before(jiffies,dentry->d_time+NFS_ATTRTIMEO(inode)))
+	if (IS_ROOT(dentry))
X 		goto out_valid;
X 
-	if (IS_ROOT(dentry))
+	if (!nfs_dentry_force_reval(dentry, flags))
X 		goto out_valid;
X 
-do_lookup:
X 	/*
X 	 * Do a new lookup and check the dentry attributes.
X 	 */
-	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), 
+	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
X 				dentry->d_name.name, &fhandle, &fattr);
-	if (dentry->d_inode == NULL) {
-		if (error == -ENOENT &&
-		    time_before(jiffies,dentry->d_time+NFS_REVALIDATE_INTERVAL))
-			goto out_valid;
-		goto out_bad;
-	}
X 	if (error)
X 		goto out_bad;
X 
@@ -496,7 +531,7 @@
X }
X 
X struct dentry_operations nfs_dentry_operations = {
-	nfs_lookup_revalidate,	/* d_validate(struct dentry *) */
+	nfs_lookup_revalidate,	/* d_revalidate(struct dentry *, int) */
X 	NULL,			/* d_hash */
X 	NULL,			/* d_compare */
X 	nfs_dentry_delete,	/* d_delete(struct dentry *) */
diff -u --recursive --new-file v2.2.7/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.2.7/linux/fs/nfs/file.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/nfs/file.c	Sat May  8 20:01:19 1999
@@ -46,9 +46,9 @@
X 	NULL,			/* select - default */
X 	NULL,			/* ioctl - default */
X 	nfs_file_mmap,		/* mmap */
-	NULL,			/* no special open is needed */
+	nfs_open,		/* open */
X 	nfs_file_flush,		/* flush */
-	NULL,			/* release */
+	nfs_release,		/* release */
X 	nfs_fsync,		/* fsync */
X 	NULL,			/* fasync */
X 	NULL,			/* check_media_change */
diff -u --recursive --new-file v2.2.7/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.2.7/linux/fs/nfs/inode.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/nfs/inode.c	Sat May  8 20:00:46 1999
@@ -696,6 +696,22 @@
X }
X 
X /*
+ * These are probably going to contain hooks for
+ * allocating and releasing RPC credentials for
+ * the file. I'll have to think about Tronds patch
+ * a bit more..
+ */
+int nfs_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+int nfs_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+/*
X  * This function is called whenever some part of NFS notices that
X  * the cached attributes have to be refreshed.
X  */
diff -u --recursive --new-file v2.2.7/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.2.7/linux/fs/proc/array.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/proc/array.c	Mon May 10 10:05:18 1999
@@ -896,7 +896,7 @@
X 
X 	return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
X %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
X 		pid,
X 		tsk->comm,
X 		state,
@@ -938,7 +938,8 @@
X 		wchan,
X 		tsk->nswap,
X 		tsk->cnswap,
-		tsk->exit_signal);
+		tsk->exit_signal,
+		tsk->processor);
X }
X 		
X static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
diff -u --recursive --new-file v2.2.7/linux/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- v2.2.7/linux/fs/qnx4/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/qnx4/namei.c	Mon May 10 14:14:28 1999
@@ -70,12 +70,8 @@
X 	struct buffer_head *bh;
X 
X 	*res_dir = NULL;
-	if (!dir || !dir->i_sb) {
-		if (!dir) {
-			printk("qnx4: NULL dir.\n");
-		} else {
-			printk("qnx4: no superblock on dir.\n");
-		}
+	if (!dir->i_sb) {
+		printk("qnx4: no superblock on dir.\n");
X 		return NULL;
X 	}
X 	bh = NULL;
diff -u --recursive --new-file v2.2.7/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.2.7/linux/fs/smbfs/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/smbfs/dir.c	Sat May  8 17:56:37 1999
@@ -191,14 +191,14 @@
X /*
X  * Dentry operations routines
X  */
-static int smb_lookup_validate(struct dentry *);
+static int smb_lookup_validate(struct dentry *, int);
X static int smb_hash_dentry(struct dentry *, struct qstr *);
X static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
X static void smb_delete_dentry(struct dentry *);
X 
X static struct dentry_operations smbfs_dentry_operations =
X {
-	smb_lookup_validate,	/* d_validate(struct dentry *) */
+	smb_lookup_validate,	/* d_revalidate(struct dentry *) */
X 	smb_hash_dentry,	/* d_hash */
X 	smb_compare_dentry,	/* d_compare */
X 	smb_delete_dentry	/* d_delete(struct dentry *) */
@@ -208,7 +208,7 @@
X  * This is the callback when the dcache has a lookup hit.
X  */
X static int
-smb_lookup_validate(struct dentry * dentry)
+smb_lookup_validate(struct dentry * dentry, int flags)
X {
X 	struct inode * inode = dentry->d_inode;
X 	unsigned long age = jiffies - dentry->d_time;
diff -u --recursive --new-file v2.2.7/linux/fs/super.c linux/fs/super.c
--- v2.2.7/linux/fs/super.c	Fri Apr 16 14:47:31 1999
+++ linux/fs/super.c	Mon May 10 10:08:51 1999
@@ -1131,6 +1131,7 @@
X 			sb = get_empty_super(); /* "can't fail" */
X 			sb->s_dev = get_unnamed_dev();
X 			sb->s_flags = root_mountflags;
+			sema_init(&sb->s_vfs_rename_sem,1);
X 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
X 			if (vfsmnt) {
X 				if (nfs_root_mount(sb) >= 0) {
@@ -1156,12 +1157,22 @@
X 
X #ifdef CONFIG_BLK_DEV_FD
X 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+#ifdef CONFIG_BLK_DEV_RAM
+		extern int rd_doload;
+#endif
X 		floppy_eject();
X #ifndef CONFIG_BLK_DEV_RAM
X 		printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
+#else
+		/* rd_doload is 2 for a dual initrd/ramload setup */
+		if(rd_doload==2)
+			rd_load_secondary();
+		else
X #endif
-		printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
-		wait_for_keypress();
+		{
+			printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
+			wait_for_keypress();
+		}
X 	}
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.2.7/linux/fs/sysv/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/sysv/namei.c	Mon May 10 14:14:28 1999
@@ -67,8 +67,6 @@
X 	struct buffer_head * bh;
X 
X 	*res_dir = NULL;
-	if (!dir)
-		return NULL;
X 	sb = dir->i_sb;
X 	if (namelen > SYSV_NAMELEN) {
X 		if (sb->sv_truncate)
diff -u --recursive --new-file v2.2.7/linux/fs/ufs/namei.c linux/fs/ufs/namei.c
--- v2.2.7/linux/fs/ufs/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ufs/namei.c	Mon May 10 14:14:28 1999
@@ -91,8 +91,6 @@
X 	UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen))
X 	
X 	*res_dir = NULL;
-	if (!dir) 
-		return NULL;
X 	
X 	sb = dir->i_sb;
X 	flags = sb->u.ufs_sb.s_flags;
diff -u --recursive --new-file v2.2.7/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.2.7/linux/fs/umsdos/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/umsdos/dir.c	Sat May  8 17:56:37 1999
@@ -30,7 +30,7 @@
X  */
X 
X /* nothing for now ... */
-static int umsdos_dentry_validate(struct dentry *dentry)
+static int umsdos_dentry_validate(struct dentry *dentry, int flags)
X {
X 	return 1;
X }
@@ -46,7 +46,7 @@
X 
X struct dentry_operations umsdos_dentry_operations =
X {
-	umsdos_dentry_validate,	/* d_validate(struct dentry *) */
+	umsdos_dentry_validate,	/* d_revalidate(struct dentry *, int) */
X 	NULL,			/* d_hash */
X 	NULL,			/* d_compare */
X 	umsdos_dentry_dput,	/* d_delete(struct dentry *) */
diff -u --recursive --new-file v2.2.7/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.2.7/linux/fs/vfat/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/vfat/namei.c	Sat May  8 17:56:37 1999
@@ -71,7 +71,7 @@
X static int vfat_hash(struct dentry *parent, struct qstr *qstr);
X static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
X static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
-static int vfat_revalidate(struct dentry *dentry);
+static int vfat_revalidate(struct dentry *dentry, int);
X 
X static struct dentry_operations vfat_dentry_ops[4] = {
X 	{
@@ -106,7 +106,7 @@
X 	MOD_DEC_USE_COUNT;
X }
X 
-static int vfat_revalidate(struct dentry *dentry)
+static int vfat_revalidate(struct dentry *dentry, int flags)
X {
X 	PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
X 	if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/fpu.h linux/include/asm-alpha/fpu.h
--- v2.2.7/linux/include/asm-alpha/fpu.h	Tue Mar 17 22:18:15 1998
+++ linux/include/asm-alpha/fpu.h	Mon May 10 09:55:21 1999
@@ -81,6 +81,18 @@
X 	return fp;
X }
X 
+static inline unsigned long
+ieee_fpcr_to_swcr(unsigned long fp)
+{
+	unsigned long sw;
+	sw = (fp >> 35) & IEEE_STATUS_MASK;
+	sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV
+			     | IEEE_TRAP_ENABLE_DZE
+			     | IEEE_TRAP_ENABLE_OVF);
+	sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
+	return sw;
+}
+
X #ifdef __KERNEL__
X 
X /* The following two functions don't need trapb/excb instructions
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.2.7/linux/include/asm-alpha/pgtable.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-alpha/pgtable.h	Mon May 10 09:55:21 1999
@@ -167,19 +167,6 @@
X 
X #else /* __SMP__ */
X 
-/* ipi_msg_flush_tb is owned by the holder of the global kernel lock. */
-struct ipi_msg_flush_tb_struct {
-	volatile unsigned int flush_tb_mask;
-	union {
-		struct mm_struct *	flush_mm;
-		struct vm_area_struct *	flush_vma;
-	} p;
-	unsigned long flush_addr;
-	unsigned long flush_end;
-};
-
-extern struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
-
X extern void flush_tlb_all(void);
X extern void flush_tlb_mm(struct mm_struct *);
X extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.2.7/linux/include/asm-alpha/semaphore.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-alpha/semaphore.h	Fri May  7 10:55:26 1999
@@ -190,7 +190,7 @@
X 		"	stl_c	$28,%1\n"
X 		"	beq	$28,2f\n"
X 		"	mb\n"
-		"	ble	$27,3f\n"
+		"	ble	$24,3f\n"
X 		"4:\n"
X 		".section .text2,\"ax\"\n"
X 		"2:	br	1b\n"
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.2.7/linux/include/asm-alpha/system.h	Tue Jan 19 11:32:52 1999
+++ linux/include/asm-alpha/system.h	Tue May 11 09:55:45 1999
@@ -1,6 +1,7 @@
X #ifndef __ALPHA_SYSTEM_H
X #define __ALPHA_SYSTEM_H
X 
+#include <linux/config.h>
X #include <asm/pal.h>
X #include <asm/page.h>
X 
@@ -97,12 +98,15 @@
X 
X extern void halt(void) __attribute__((noreturn));
X 
-#define switch_to(prev,next) do {					\
-	current = next;							\
-	alpha_switch_to((unsigned long) ¤t->tss - IDENT_ADDR);	\
+#define switch_to(prev,next,last)			\
+do {							\
+	unsigned long pcbb;				\
+	current = (next);				\
+	pcbb = virt_to_phys(¤t->tss);		\
+	(last) = alpha_switch_to(pcbb, (prev));		\
X } while (0)
X 
-extern void alpha_switch_to(unsigned long pctxp);
+extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*);
X 
X #define mb() \
X __asm__ __volatile__("mb": : :"memory")
@@ -119,6 +123,34 @@
X #define draina() \
X __asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory")
X 
+enum implver_enum {
+	IMPLVER_EV4,
+	IMPLVER_EV5,
+	IMPLVER_EV6
+};
+
+#ifdef CONFIG_ALPHA_GENERIC
+#define implver()				\
+({ unsigned long __implver;			\
+   __asm__ ("implver %0" : "=r"(__implver));	\
+   (enum implver_enum) __implver; })
+#else
+/* Try to eliminate some dead code.  */
+#ifdef CONFIG_ALPHA_EV4
+#define implver() IMPLVER_EV4
+#endif
+#ifdef CONFIG_ALPHA_EV5
+#define implver() IMPLVER_EV5
+#endif
+#ifdef CONFIG_ALPHA_EV6
+#define implver() IMPLVER_EV6
+#endif
+#endif
+
+#define amask(mask)						\
+({ unsigned long __amask, __input = (mask);			\
+   __asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input));	\
+   __amask; })
X 
X static inline unsigned long 
X wrperfmon(unsigned long perf_fun, unsigned long arg)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h
--- v2.2.7/linux/include/asm-arm/a.out.h	Fri Jan  8 22:36:15 1999
+++ linux/include/asm-arm/a.out.h	Sat May  8 11:06:57 1999
@@ -26,7 +26,9 @@
X 
X #define M_ARM 103
X 
+#ifdef __KERNEL__
X #include <asm/arch/a.out.h>
+#endif
X 
X #ifndef LIBRARY_START_TEXT
X #define LIBRARY_START_TEXT	(0x00c00000)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/a.out.h linux/include/asm-arm/arch-arc/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-arc/a.out.h	Fri Jan  8 22:36:17 1999
+++ linux/include/asm-arm/arch-arc/a.out.h	Sat May  8 11:06:57 1999
@@ -1,16 +1,14 @@
X /*
X  * linux/include/asm-arm/arch-arc/a.out.h
X  *
- * Copyright (C) 1996 Russell King
- *
- * Acorn Archimedes/A5000 a.out.h specs
+ * Copyright (C) 1996-1999 Russell King
X  */
X #ifndef __ASM_ARCH_A_OUT_H
X #define __ASM_ARCH_A_OUT_H
X 
-#ifdef __KERNEL__
-#define STACK_TOP		(0x01a00000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP	TASK_SIZE
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-arc/hardware.h	Fri Jan  8 22:36:18 1999
+++ linux/include/asm-arm/arch-arc/hardware.h	Sat May  8 11:06:57 1999
@@ -1,7 +1,7 @@
X /*
X  * linux/include/asm-arm/arch-arc/hardware.h
X  *
- * Copyright (C) 1996 Russell King.
+ * Copyright (C) 1996-1999 Russell King.
X  *
X  * This file contains the hardware definitions of the
X  * Acorn Archimedes/A5000 machines.
@@ -9,21 +9,20 @@
X  * Modifications:
X  *  04-04-1998	PJB/RMK	Merged arc and a5k versions
X  */
-
X #ifndef __ASM_ARCH_HARDWARE_H
X #define __ASM_ARCH_HARDWARE_H
X 
X #include <linux/config.h>
X 
+#include <asm/arch/memory.h>
+
X /*
X  * What hardware must be present - these can be tested by the kernel
X  * source.
X  */
X #define HAS_IOC
-#include <asm/ioc.h>
X #define HAS_MEMC
X #include <asm/memc.h>
-#define HAS_MEMC1A
X #define HAS_VIDC
X 
X /*
@@ -56,6 +55,12 @@
X  * for use with inb/outb
X  */
X #define IO_VIDC_BASE		0x80100000
+#ifdef CONFIG_ARCH_A5K
+#define IOEB_VID_CTL		0x800d4012
+#define IOEB_PRESENT		0x800d4014
+#define IOEB_PSCLR		0x800d4016
+#define IOEB_MONTYPE		0x800d401c
+#endif
X #ifdef CONFIG_ARCH_ARC
X #define LATCHAADDR		0x80094010
X #define LATCHBADDR		0x80094006
@@ -66,6 +71,14 @@
X #define IO_EC_IOC_BASE		0x80090000
X #define IO_EC_MEMC_BASE		0x80000000
X 
+#ifdef CONFIG_ARCH_ARC
+/* A680 hardware */
+#define WD1973_BASE		0x03290000
+#define WD1973_LATCH		0x03350000
+#define Z8530_BASE		0x032b0008
+#define SCSI_BASE		0x03100000
+#endif
+
X /*
X  * IO definitions
X  */
@@ -77,11 +90,8 @@
X /*
X  * RAM definitions
X  */
-#define MAPTOPHYS(a)		(((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a)		((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
X #define GET_MEMORY_END(p)	(PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
X #define PARAMS_BASE		(PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE		(PAGE_OFFSET + 0x80000)
X 
X #else
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h
--- v2.2.7/linux/include/asm-arm/arch-arc/irq.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-arc/irq.h	Sat May  8 11:06:57 1999
@@ -10,6 +10,9 @@
X  *   11-01-1998	RMK	Added mask_and_ack_irq
X  *   22-08-1998	RMK	Restructured IRQ routines
X  */
+#include <asm/ioc.h>
+
+#define fixup_irq(x) (x)
X 
X static void arc_mask_irq_ack_a(unsigned int irq)
X {
@@ -108,10 +111,17 @@
X 	outb(0, IOC_FIQMASK);
X 
X 	for (irq = 0; irq < NR_IRQS; irq++) {
-		switch (irq & 0xf8) {
+		switch (irq) {
X 		case 0 ... 6:
X 			irq_desc[irq].probe_ok = 1;
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
+			irq_desc[irq].mask     = arc_mask_irq_a;
+			irq_desc[irq].unmask   = arc_unmask_irq_a;
+			break;
+
X 		case 7:
+			irq_desc[irq].noautoenable = 1;
X 			irq_desc[irq].valid    = 1;
X 			irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
X 			irq_desc[irq].mask     = arc_mask_irq_a;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/keyboard.h linux/include/asm-arm/arch-arc/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-arc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-arc/keyboard.h	Sat May  8 11:06:57 1999
@@ -11,7 +11,6 @@
X 
X #define NR_SCANCODES 128
X 
-extern int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
X extern void a5kkbd_leds(unsigned char leds);
X extern void a5kkbd_init_hw(void);
X extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
@@ -19,11 +18,7 @@
X #define kbd_setkeycode(sc,kc)		(-EINVAL)
X #define kbd_getkeycode(sc)		(-EINVAL)
X 
-/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
- * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
- *            set to 0200 if scancode indicates release
- */
-#define kbd_translate(sc, kcp, ufp, rm)	a5kkbd_translate(sc, kcp, ufp)
+#define kbd_translate(sc, kcp, rm)	({ *(kcp) = (sc); 1; })
X #define kbd_unexpected_up(kc)		(0200)
X #define kbd_leds(leds)			a5kkbd_leds(leds)
X #define kbd_init_hw()			a5kkbd_init_hw()
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/memory.h linux/include/asm-arm/arch-arc/memory.h
--- v2.2.7/linux/include/asm-arm/arch-arc/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-arc/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-arm/arch-arc/memory.h
+ *
+ * Copyright (c) 1996-1999 Russell King.
+ *
+ * Changelog:
+ *  22-Nov-1996	RMK	Created
+ *  21-Mar-1999	RMK	Renamed to memory.h
+ *		RMK	Moved PAGE_OFFSET and TASK_SIZE here
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * User space: 26MB
+ */
+#define TASK_SIZE	(0x01a00000UL)
+
+/*
+ * Page offset: 32MB
+ */
+#define PAGE_OFFSET	(0x02000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) vpage
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ppage
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	(x)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/mmu.h linux/include/asm-arm/arch-arc/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-arc/mmu.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-arc/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,29 +0,0 @@
-/*
- * linux/include/asm-arm/arch-arc/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  22-11-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ppage
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	(x)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	(x)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/oldlatches.h linux/include/asm-arm/arch-arc/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-arc/oldlatches.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-arc/oldlatches.h	Sat May  8 11:06:57 1999
@@ -34,6 +34,8 @@
X /* newval=(oldval & mask)|newdata */
X void oldlatch_aupdate(unsigned char mask,unsigned char newdata);
X 
+void oldlatch_init(void);
+
X #elif defined(CONFIG_ARCH_A5K)
X 
X #ifdef __need_oldlatches
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/processor.h linux/include/asm-arm/arch-arc/processor.h
--- v2.2.7/linux/include/asm-arm/arch-arc/processor.h	Fri Jan  8 22:36:20 1999
+++ linux/include/asm-arm/arch-arc/processor.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,18 @@
X /*
X  * linux/include/asm-arm/arch-arc/processor.h
X  *
- * Copyright (c) 1996 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
X  *
X  * Changelog:
- *  10-09-1996	RMK	Created
+ *  10-Sep-1996	RMK	Created
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
X  */
X 
X #ifndef __ASM_ARCH_PROCESSOR_H
X #define __ASM_ARCH_PROCESSOR_H
X 
+#include <asm/arch/memory.h>
+
X /*
X  * Bus types
X  */
@@ -18,17 +21,9 @@
X #define MCA_bus 0
X #define MCA_bus__is_a_macro /* for versions in ksyms.c */
X 
-/*
- * User space: 26MB
- */
-#define TASK_SIZE	(0x01a00000UL)
-
X /* This decides where the kernel will search for a free chunk of vm
X  * space during mmap's.
X  */
X #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/time.h linux/include/asm-arm/arch-arc/time.h
--- v2.2.7/linux/include/asm-arm/arch-arc/time.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/time.h	Sat May  8 11:06:57 1999
@@ -8,6 +8,9 @@
X  *  10-Oct-1996	RMK	Brought up to date with arch-sa110eval
X  *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
X  */
+#include <asm/ioc.h>
+
+static long last_rtc_update = 0;	/* last time the cmos clock got updated */
X 
X extern __inline__ unsigned long gettimeoffset (void)
X {
@@ -51,46 +54,140 @@
X 	return offset;
X }
X 
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
+extern int iic_control (unsigned char, int, char *, int);
X 
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 25'
echo 'File patch-2.2.8 is continued in part 26'
echo 26 > _shar_seq_.tmp
#!/bin/sh
# this is part 26 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 26; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
-#define update_rtc()
+static int set_rtc_time(unsigned long nowtime)
+{
+	char buf[5], ctrl;
+
+	if (iic_control(0xa1, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to read control reg\n");
+
+	/*
+	 * Reset divider
+	 */
+	ctrl |= 0x80;
+
+	if (iic_control(0xa0, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to stop the clock\n");
+
+	/*
+	 * We only set the time - we don't set the date.
+	 * This means that there is the possibility once
+	 * a day for the correction to disrupt the date.
+	 * We really ought to write the time and date, or
+	 * nothing at all.
+	 */
+	buf[0] = 0;
+	buf[1] = nowtime % 60;		nowtime /= 60;
+	buf[2] = nowtime % 60;		nowtime /= 60;
+	buf[3] = nowtime % 24;
+
+	BIN_TO_BCD(buf[1]);
+	BIN_TO_BCD(buf[2]);
+	BIN_TO_BCD(buf[3]);
+
+	if (iic_control(0xa0, 1, buf, 4) != 0)
+		printk("RTC: Failed to set the time\n");
+
+	/*
+	 * Re-enable divider
+	 */
+	ctrl &= ~0x80;
+
+	if (iic_control(0xa0, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to start the clock\n");
+
+	return 0;
+}
+
+extern __inline__ unsigned long get_rtc_time(void)
+{
+	unsigned int year, i;
+	char buf[8];
+
+	/*
+	 * The year is not part of the RTC counter
+	 * registers, and is stored in RAM.  This
+	 * means that it will not be automatically
+	 * updated.
+	 */
+	if (iic_control(0xa1, 0xc0, buf, 1) != 0)
+		printk("RTC: failed to read the year\n");
+
+	/*
+	 * If the year is before 1970, then the year
+	 * is actually 100 in advance.  This gives us
+	 * a year 2070 bug...
+	 */
+	year = 1900 + buf[0];
+	if (year < 1970)
+		year += 100;
+
+	/*
+	 * Read the time and date in one go - this
+	 * will ensure that we don't get any effects
+	 * due to carry (the RTC latches the counters
+	 * during a read).
+	 */
+	if (iic_control(0xa1, 2, buf, 5) != 0) {
+		printk("RTC: failed to read the time and date\n");
+		memset(buf, 0, sizeof(buf));
+	}
+
+	/*
+	 * The RTC combines years with date and weekday
+	 * with month.  We need to mask off this extra
+	 * information before converting the date to
+	 * binary.
+	 */
+	buf[4] &= 0x1f;
+	buf[3] &= 0x3f;
+
+	for (i = 0; i < 5; i++)
+		BCD_TO_BIN(buf[i]);
+
+	return mktime(year, buf[4], buf[3], buf[2], buf[1], buf[0]);
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec >= 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		if (set_rtc_time(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+}
+
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
X 
X /*
X  * Set up timer interrupt, and return the current time in seconds.
X  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
X {
-	extern int iic_control (unsigned char, int, char *, int);
-	unsigned int year, mon, day, hour, min, sec;
-	char buf[8];
-
X 	outb(LATCH & 255, IOC_T0LTCHL);
X 	outb(LATCH >> 8, IOC_T0LTCHH);
X 	outb(0, IOC_T0GO);
X 
-	iic_control (0xa0, 0xc0, buf, 1);
-	year = buf[0];
-	if ((year += 1900) < 1970)
-		year += 100;
-
-	iic_control (0xa0, 2, buf, 5);
-	mon  = buf[4] & 0x1f;
-	day  = buf[3] & 0x3f;
-	hour = buf[2];
-	min  = buf[1];
-	sec  = buf[0];
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(sec);
+	xtime.tv_sec = get_rtc_time();
X 
-	return mktime(year, mon, day, hour, min, sec);
+	setup_arm_irq(IRQ_TIMER, &timerirq);
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/uncompress.h linux/include/asm-arm/arch-arc/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-arc/uncompress.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-arc/uncompress.h	Sat May  8 11:06:57 1999
@@ -5,8 +5,6 @@
X  */
X #define VIDMEM ((char *)0x02000000)
X  
-#include "../arch/arm/drivers/char/font.h"
-
X int video_num_columns, video_num_lines, video_size_row;
X int white, bytes_per_char_h;
X extern unsigned long con_charconvtable[256];
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/a.out.h linux/include/asm-arm/arch-ebsa110/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/a.out.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
X /*
X  * linux/include/asm-arm/arch-ebsa110/a.out.h
X  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
X  */
-
X #ifndef __ASM_ARCH_A_OUT_H
X #define __ASM_ARCH_A_OUT_H
X 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/hardware.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Sat May  8 11:06:57 1999
@@ -1,19 +1,13 @@
X /*
X  * linux/include/asm-arm/arch-ebsa110/hardware.h
X  *
- * Copyright (C) 1996,1997,1998 Russell King.
+ * Copyright (C) 1996-1999 Russell King.
X  *
X * This file contains the hardware definitions of the EBSA-110.
X  */
-
X #ifndef __ASM_ARCH_HARDWARE_H
X #define __ASM_ARCH_HARDWARE_H
X 
-/*
- * What hardware must be present
- */
-#define HAS_PCIO
-
X #ifndef __ASSEMBLER__
X 
X /*
@@ -23,28 +17,28 @@
X #define PIT_T2			((volatile unsigned char *)0xf2000009)
X #define PIT_T1			((volatile unsigned char *)0xf2000005)
X #define PIT_T0			((volatile unsigned char *)0xf2000001)
-#define PCIO_BASE		0xf0000000
X 
X /*
X  * Mapping areas
X  */
X #define IO_BASE			0xe0000000
-#define IO_SIZE			0x20000000
-#define IO_START		0xe0000000
X 
X /*
X  * RAM definitions
X  */
-#define MAPTOPHYS(a)		((unsigned long)(a) - PAGE_OFFSET)
-#define KERNTOPHYS(a)		((unsigned long)(&a))
-#define KERNEL_BASE		(0xc0008000)
X #define FLUSH_BASE_PHYS		0x40000000
X 
X #else
X 
-#define PCIO_BASE		0xf0000000
X #define IO_BASE			0
X 
X #endif
+
+#define IO_SIZE			0x20000000
+#define IO_START		0xe0000000
+
+#define FLUSH_BASE		0xdf000000
+#define PCIO_BASE		0xf0000000
+
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/irq.h linux/include/asm-arm/arch-ebsa110/irq.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/irq.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-ebsa110/irq.h	Sat May  8 11:06:57 1999
@@ -11,6 +11,8 @@
X #define IRQ_MSET	((volatile unsigned char *)0xf2c00000)
X #define IRQ_MASK	((volatile unsigned char *)0xf2c00000)
X 
+#define fixup_irq(x) (x)
+
X static void ebsa110_mask_and_ack_irq(unsigned int irq)
X {
X 	*IRQ_MCLR = 1 << irq;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/memory.h linux/include/asm-arm/arch-ebsa110/memory.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa110/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/memory.h
+ *
+ * Copyright (c) 1996-1999 Russell King.
+ *
+ * Changelog:
+ *  20-Oct-1996	RMK	Created
+ *  31-Dec-1997	RMK	Fixed definitions to reduce warnings
+ *  21-Mar-1999	RMK	Renamed to memory.h
+ * RMK Moved TASK_SIZE and PAGE_OFFSET here
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	__phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/mm-init.h linux/include/asm-arm/arch-ebsa110/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/mm-init.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-ebsa110/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/mmu.h linux/include/asm-arm/arch-ebsa110/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/mmu.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-ebsa110/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
-
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	__virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	__phys_to_virt(x)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/oldlatches.h linux/include/asm-arm/arch-ebsa110/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/oldlatches.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/processor.h linux/include/asm-arm/arch-ebsa110/processor.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/processor.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/processor.h	Sat May  8 11:06:57 1999
@@ -1,12 +1,17 @@
X /*
X  * linux/include/asm-arm/arch-ebsa110/processor.h
X  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
X  */
X 
X #ifndef __ASM_ARCH_PROCESSOR_H
X #define __ASM_ARCH_PROCESSOR_H
X 
+#include <asm/arch/memory.h>
+
X /*
X  * Bus types
X  */
@@ -15,17 +20,9 @@
X #define MCA_bus 0
X #define MCA_bus__is_a_macro /* for versions in ksyms.c */
X 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
X /* This decides where the kernel will search for a free chunk of vm
X  * space during mmap's.
X  */
X #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/time.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/time.h	Sat May  8 11:06:57 1999
@@ -38,63 +38,67 @@
X 	return 0;
X }
X 
-#ifndef DIVISOR
-extern __inline__ int reset_timer (void)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
X {
X 	*PIT_T1 = (PIT1_COUNT) & 0xff;
X 	*PIT_T1 = (PIT1_COUNT) >> 8;
-	return 1;
-}
-#else
-extern __inline__ int reset_timer (void)
-{
-	static unsigned int divisor;
-#ifdef CONFIG_LEDS	
-	static int count = 50;
-#endif
-
-	*PIT_T1 = (PIT1_COUNT) & 0xff;
-	*PIT_T1 = (PIT1_COUNT) >> 8;
X 
X #ifdef CONFIG_LEDS
-	if (--count == 0) {
-		count = 50;
-		leds_event(led_timer);
+	{
+		static int count = 50;
+		if (--count == 0) {
+			count = 50;
+			leds_event(led_timer);
+		}
X 	}
X #endif
X 
-	if (divisor == 0) {
-		divisor = DIVISOR - 1;
-		return 1;
+	{
+#ifdef DIVISOR
+		static unsigned int divisor;
+
+		if (divisor-- == 0) {
+			divisor = DIVISOR - 1;
+#else
+		{
+#endif
+			do_timer(regs);
+		}
X 	}
-	divisor -= 1;
-	return 0;
X }
-#endif
X 
-/*
- * We don't have a RTC to update!
- */
-#define update_rtc()
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
X 
X /*
X  * Set up timer interrupt, and return the current time in seconds.
X  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
X {
X 	/*
X 	 * Timer 1, mode 0, 16-bit, autoreload
X 	 */
X 	*PIT_CTRL = 0x70;
+
X 	/*
X 	 * Refresh counter clocked at 47.8MHz/7 = 146.4ns
X 	 * We want centi-second interrupts
X 	 */
-	reset_timer ();
+	*PIT_T1 = (PIT1_COUNT) & 0xff;
+	*PIT_T1 = (PIT1_COUNT) >> 8;
+
X 	/*
X 	 * Default the date to 1 Jan 1970 0:0:0
X 	 * You will have to run a time daemon to set the
X 	 * clock correctly at bootup
X 	 */
-	return mktime(1970, 1, 1, 0, 0, 0);
+	xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
+
+	setup_arm_irq(IRQ_TIMER, &timerirq);
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/a.out.h linux/include/asm-arm/arch-ebsa285/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/a.out.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
X /*
X  * linux/include/asm-arm/arch-ebsa110/a.out.h
X  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
X  */
-
X #ifndef __ASM_ARCH_A_OUT_H
X #define __ASM_ARCH_A_OUT_H
X 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/dma.h linux/include/asm-arm/arch-ebsa285/dma.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/dma.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/dma.h	Sat May  8 11:06:57 1999
@@ -3,8 +3,8 @@
X  *
X  * Architecture DMA routines
X  *
- * Copyright (C) 1998 Russell King
- * Copyright (C) 1998 Philip Blundell
+ * Copyright (C) 1998,1999 Russell King
+ * Copyright (C) 1998,1999 Philip Blundell
X  */
X #ifndef __ASM_ARCH_DMA_H
X #define __ASM_ARCH_DMA_H
@@ -15,12 +15,16 @@
X #define MAX_DMA_ADDRESS		0xffffffff
X 
X /*
- * The 21285 has two internal DMA channels; we call these 0 and 1.
+ * The 21285 has two internal DMA channels; we call these 8 and 9.
X  * On CATS hardware we have an additional eight ISA dma channels
- * numbered 2..9.
+ * numbered 0..7.
X  */
+#define _ISA_DMA(x)		(0+(x))
+#define _DC21285_DMA(x)		(8+(x))
+
X #define MAX_DMA_CHANNELS	10
-#define DMA_ISA_BASE		2
-#define DMA_FLOPPY		(DMA_ISA_BASE + 2)
+
+#define DMA_FLOPPY		_ISA_DMA(2)
+#define DMA_ISA_CASCADE		_ISA_DMA(4)
X 
X #endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/hardware.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/hardware.h	Sat May  8 11:06:57 1999
@@ -1,47 +1,135 @@
X /*
X  * linux/include/asm-arm/arch-ebsa285/hardware.h
X  *
- * Copyright (C) 1998 Russell King.
+ * Copyright (C) 1998-1999 Russell King.
X  *
X  * This file contains the hardware definitions of the EBSA-285.
X  */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
X 
+#include <linux/config.h>
+#include <asm/arch/memory.h>
X 
-/*    Logical    Physical
+#ifdef CONFIG_HOST_FOOTBRIDGE
+/*   Virtual      Physical
X  * 0xfff00000	0x40000000	X-Bus
- * 0xffe00000	0x7c000000	PCI I/O space
+ * 0xff000000	0x7c000000	PCI I/O space
X  *
X  * 0xfe000000	0x42000000	CSR
X  * 0xfd000000	0x78000000	Outbound write flush
X  * 0xfc000000	0x79000000	PCI IACK/special space
X  *
- * 0xf9000000	0x7a010000	PCI Config type 1
- * 0xf8000000	0x7b010000	PCI Config type 0
+ * 0xf9000000	0x7a000000	PCI Config type 1
+ * 0xf8000000	0x7b000000	PCI Config type 0
X  * 
X  */
+#define XBUS_SIZE		0x00100000
+#define XBUS_BASE		0xfff00000
X 
-#include <asm/dec21285.h>
- 
-#define IO_BASE			0xe0000000
-#define PCIO_BASE		0xffe00000
-#define PCI_IACK		0xfc000000 
+#define PCIO_SIZE		0x00100000
+#define PCIO_BASE		0xff000000
X 
-#define XBUS_LEDS		((volatile unsigned char *)0xfff12000)
+#define ARMCSR_SIZE		0x01000000
+#define ARMCSR_BASE		0xfe000000
+
+#define WFLUSH_SIZE		0x01000000
+#define WFLUSH_BASE		0xfd000000
+
+#define PCIIACK_SIZE		0x01000000
+#define PCIIACK_BASE		0xfc000000
+
+#define PCICFG1_SIZE		0x01000000
+#define PCICFG1_BASE		0xf9000000
+
+#define PCICFG0_SIZE		0x01000000
+#define PCICFG0_BASE		0xf8000000
+
+#define PCIMEM_SIZE		0x18000000
+#define PCIMEM_BASE		0xe0000000
+
+#define FLUSH_SIZE		0x00100000
+#define FLUSH_BASE		0xdf000000
+
+#define FLASH_SIZE		0x00400000
+#define FLASH_BASE		0xd8000000
+
+#elif defined(CONFIG_ARCH_CO285)
+
+#define PCIMEM_SIZE		0x80000000
+#define PCIMEM_BASE		0x80000000
+
+#define FLASH_SIZE		0x01000000
+#define FLASH_BASE		0x7f000000
+
+#define FLUSH_SIZE		0x00100000
+#define FLUSH_BASE		0x7e000000
+
+#define WFLUSH_SIZE		0x01000000
+#define WFLUSH_BASE		0x7d000000
+
+#define ARMCSR_SIZE		0x00100000
+#define ARMCSR_BASE		0x7cf00000
+
+#define XBUS_SIZE		0x00020000
+#define XBUS_BASE		0x7cee0000
+
+#define PCIO_SIZE		0x00010000
+#define PCIO_BASE		0x7ced0000
+
+#else
+
+#error Add your add-in architecture here
+
+#endif
+
+#define XBUS_LEDS		((volatile unsigned char *)(XBUS_BASE + 0x12000))
X #define XBUS_LED_AMBER		(1 << 0)
X #define XBUS_LED_GREEN		(1 << 1)
X #define XBUS_LED_RED		(1 << 2)
X #define XBUS_LED_TOGGLE		(1 << 8)
X 
-#define XBUS_SWITCH		((volatile unsigned char *)0xfff12000)
+#define XBUS_SWITCH		((volatile unsigned char *)(XBUS_BASE + 0x12000))
X #define XBUS_SWITCH_SWITCH	((*XBUS_SWITCH) & 15)
X #define XBUS_SWITCH_J17_13	((*XBUS_SWITCH) & (1 << 4))
X #define XBUS_SWITCH_J17_11	((*XBUS_SWITCH) & (1 << 5))
X #define XBUS_SWITCH_J17_9	((*XBUS_SWITCH) & (1 << 6))
X 
-#define KERNTOPHYS(a)		((unsigned long)(&a))
-
X #define PARAMS_OFFSET		0x0100
X #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
X 
X #define FLUSH_BASE_PHYS		0x50000000
X 
+
+/* PIC irq control */
+#define PIC_LO			0x20
+#define PIC_MASK_LO		0x21
+#define PIC_HI			0xA0
+#define PIC_MASK_HI		0xA1
+
+/* GPIO pins */
+#define GPIO_CCLK		0x800
+#define GPIO_DSCLK		0x400
+#define GPIO_E2CLK		0x200
+#define GPIO_IOLOAD		0x100
+#define GPIO_RED_LED		0x080
+#define GPIO_WDTIMER		0x040
+#define GPIO_DATA		0x020
+#define GPIO_IOCLK		0x010
+#define GPIO_DONE		0x008
+#define GPIO_FAN		0x004
+#define GPIO_GREEN_LED		0x002
+#define GPIO_RESET		0x001
+
+/* CPLD pins */
+#define CPLD_DSRESET		8
+#define CPLD_UNMUTE		2
+
+#ifndef __ASSEMBLY__
+extern void gpio_modify_op(int mask, int set);
+extern void gpio_modify_io(int mask, int in);
+extern int  gpio_read(void);
+extern void cpld_modify(int mask, int set);
+#endif
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/io.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/io.h	Sat May  8 11:06:57 1999
@@ -16,34 +16,37 @@
X  * has the constant-optimised IO
X  */
X #undef	ARCH_IO_DELAY
+#define ARCH_READWRITE
X 
X /*
X  * Dynamic IO functions - let the compiler
X  * optimize the expressions
X  */
-#define DECLARE_DYN_OUT(fnsuffix,instr,typ)					\
-extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
-{										\
-	__asm__ __volatile__(							\
-	"str%?" ##instr## "	%0, [%1, %2]		@ out"###fnsuffix	\
-	: 									\
-	: "r" (value), "r" (PCIO_BASE), typ (port));				\
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)					\
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
-{										\
-	unsigned long value;							\
-	__asm__ __volatile__(							\
-	"ldr%?" ##instr## "	%0, [%1, %2]		@ in"###fnsuffix	\
-	: "=&r" (value)								\
-	: "r" (PCIO_BASE), typ (port));						\
-	return (unsigned sz)value;						\
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)			\
-{										\
-	return (unsigned int)(PCIO_BASE + port);				\
+#define DECLARE_DYN_OUT(fnsuffix,instr,typ)				\
+extern __inline__ void							\
+__out##fnsuffix (unsigned int value, unsigned int port)			\
+{									\
+	__asm__ __volatile__(						\
+	"str%?" ##instr## "	%0, [%1, %2]	@ out"###fnsuffix	\
+	: 								\
+	: "r" (value), "r" (PCIO_BASE), typ (port));			\
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)				\
+extern __inline__ unsigned sz						\
+__in##fnsuffix (unsigned int port)					\
+{									\
+	unsigned long value;						\
+	__asm__ __volatile__(						\
+	"ldr%?" ##instr## "	%0, [%1, %2]	@ in"###fnsuffix	\
+	: "=&r" (value)							\
+	: "r" (PCIO_BASE), typ (port));					\
+	return (unsigned sz)value;					\
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port)		\
+{									\
+	return (unsigned int)(PCIO_BASE + port);			\
X }
X 
X #define DECLARE_IO(sz,fnsuffix,instr,typ)	\
@@ -64,65 +67,65 @@
X  * These have to be macros for the 'J' constraint to work -
X  * +/-4096 immediate operand.
X  */
-#define __outbc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str%?b	%0, [%1, %2]				@ outbc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inbc(port)								\
-({										\
-	unsigned char result;							\
-	__asm__ __volatile__(							\
-	"ldr%?b	%0, [%1, %2]				@ inbc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __outwc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str%?h	%0, [%1, %2]				@ outwc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "r" (port));				\
-})
-
-#define __inwc(port)								\
-({										\
-	unsigned short result;							\
-	__asm__ __volatile__(							\
-	"ldr%?h	%0, [%1, %2]				@ inwc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "r" (port));						\
-	result & 0xffff;							\
-})
-
-#define __outlc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str%?	%0, [%1, %2]				@ outlc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inlc(port)								\
-({										\
-	unsigned long result;							\
-	__asm__ __volatile__(							\
-	"ldr%?	%0, [%1, %2]				@ inlc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	addr = PCIO_BASE + port;						\
-	addr;									\
+#define __outbc(value,port)						\
+({									\
+	__asm__ __volatile__(						\
+	"str%?b	%0, [%1, %2]				@ outbc"	\
+	:								\
+	: "r" (value), "r" (PCIO_BASE), "Jr" (port));			\
+})
+
+#define __inbc(port)							\
+({									\
+	unsigned char result;						\
+	__asm__ __volatile__(						\
+	"ldr%?b	%0, [%1, %2]				@ inbc"		\
+	: "=r" (result)							\
+	: "r" (PCIO_BASE), "Jr" (port));				\
+	result;								\
+})
+
+#define __outwc(value,port)						\
+({									\
+	__asm__ __volatile__(						\
+	"str%?h	%0, [%1, %2]				@ outwc"	\
+	:								\
+	: "r" (value), "r" (PCIO_BASE), "r" (port));			\
+})
+
+#define __inwc(port)							\
+({									\
+	unsigned short result;						\
+	__asm__ __volatile__(						\
+	"ldr%?h	%0, [%1, %2]				@ inwc"		\
+	: "=r" (result)							\
+	: "r" (PCIO_BASE), "r" (port));					\
+	result & 0xffff;						\
+})
+
+#define __outlc(value,port)						\
+({									\
+	__asm__ __volatile__(						\
+	"str%?	%0, [%1, %2]				@ outlc"	\
+	:								\
+	: "r" (value), "r" (PCIO_BASE), "Jr" (port));			\
+})
+
+#define __inlc(port)							\
+({									\
+	unsigned long result;						\
+	__asm__ __volatile__(						\
+	"ldr%?	%0, [%1, %2]				@ inlc"		\
+	: "=r" (result)							\
+	: "r" (PCIO_BASE), "Jr" (port));				\
+	result;								\
+})
+
+#define __ioaddrc(port)							\
+({									\
+	unsigned long addr;						\
+	addr = PCIO_BASE + port;					\
+	addr;								\
X })
X 
X /*
@@ -130,20 +133,22 @@
X  *
X  * IO address has already been translated to a virtual address
X  */
-#define outb_t(v,p)								\
+#define outb_t(v,p)							\
X 	(*(volatile unsigned char *)(p) = (v))
X 
-#define inb_t(p)								\
+#define inb_t(p)							\
X 	(*(volatile unsigned char *)(p))
X 
-#define outl_t(v,p)								\
+#define outl_t(v,p)							\
X 	(*(volatile unsigned long *)(p) = (v))
X 
-#define inl_t(p)								\
+#define inl_t(p)							\
X 	(*(volatile unsigned long *)(p))
X 
X /*
- * ioremap support
+ * ioremap support - validate a PCI memory address,
+ * and convert a PCI memory address to a physical
+ * address for the page tables.
X  */
X #define valid_ioaddr(iomem,size) ((iomem) < 0x80000000 && (iomem) + (size) <= 0x80000000)
X #define io_to_phys(iomem)	((iomem) + DC21285_PCI_MEM)
@@ -153,58 +158,48 @@
X  * is using read*() and so on with addresses they didn't get from ioremap
X  * this can go away.
X  */
-#define IO_FUDGE_FACTOR		0xe0000000
+#define IO_FUDGE_FACTOR		PCIMEM_BASE
X 
-extern inline void *ioremap(unsigned long iomem_addr, unsigned long size)
-{
-	unsigned long phys_addr;
-
-	if (!valid_ioaddr(iomem_addr, size))
-		return NULL;
-
-	phys_addr = io_to_phys(iomem_addr & PAGE_MASK);
-
-	return (void *)((unsigned long)__ioremap(phys_addr, size, 0) 
-			- IO_FUDGE_FACTOR);
-}
+/*
+ * ioremap takes a PCI memory address, as specified in
+ * linux/Documentation/IO-mapping.txt
+ */
+#define ioremap(iomem_addr,size)					\
+({									\
+	unsigned long _addr = (iomem_addr), _size = (size);		\
+	void *_ret = NULL;						\
+	if (valid_ioaddr(_addr, _size)) {				\
+		_addr = io_to_phys(_addr);				\
+		_ret = __ioremap(_addr, _size, 0) - IO_FUDGE_FACTOR;	\
+	}								\
+	_ret; })
X 
X #define ioremap_nocache(iomem_addr,size) ioremap((iomem_addr),(size))
X 
X extern void iounmap(void *addr);
X 
-/*
- * We'd probably be better off with these as macros rather than functions.
- * Firstly that would be more efficient and secondly we could do with the
- * ability to stop GCC whinging about type conversions.  --philb
- */
-static inline void writeb(unsigned char b, unsigned int addr)
-{
-	*(volatile unsigned char *)(IO_FUDGE_FACTOR + (addr)) = b;
-}
-
-static inline unsigned char readb(unsigned int addr)
-{
-	return *(volatile unsigned char *)(IO_FUDGE_FACTOR + (addr));
+#define DECLARE_PCI_WRITE(typ,fnsuffix)					\
+static inline void write##fnsuffix(unsigned typ val, unsigned int addr)	\
+{									\
+	*(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr) = val;	\
X }
X 
-static inline void writew(unsigned short b, unsigned int addr)
-{
-	*(volatile unsigned short *)(IO_FUDGE_FACTOR + (addr)) = b;
+#define DECLARE_PCI_READ(typ,fnsuffix)					\
+static inline unsigned typ read##fnsuffix (unsigned int addr)		\
+{									\
+	return *(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr);	\
X }
X 
-static inline unsigned short readw(unsigned int addr)
-{
-	return *(volatile unsigned short *)(IO_FUDGE_FACTOR + (addr));
-}
+#define DECLARE_PCI(typ,fnsuffix)					\
+	DECLARE_PCI_WRITE(typ,fnsuffix)					\
+	DECLARE_PCI_READ(typ,fnsuffix)
X 
-static inline void writel(unsigned long b, unsigned int addr)
-{
-	*(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr)) = b;
-}
+DECLARE_PCI(char,b)
+DECLARE_PCI(short,w)
+DECLARE_PCI(long,l)
X 
-static inline unsigned short readl(unsigned int addr)
-{
-	return *(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr));
-}
+#undef DECLARE_PCI
+#undef DECLARE_PCI_READ
+#undef DECLARE_PCI_WRITE
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/irq.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Mon May 10 10:17:28 1999
@@ -4,136 +4,206 @@
X  * Copyright (C) 1996-1998 Russell King
X  *
X  * Changelog:
- *   22-08-1998	RMK	Restructured IRQ routines
- *   03-09-1998	PJB	Merged CATS support
+ *  22-Aug-1998	RMK	Restructured IRQ routines
+ *  03-Sep-1998	PJB	Merged CATS support
+ *  20-Jan-1998	RMK	Started merge of EBSA286, CATS and NetWinder
+ *  26-Jan-1999	PJB	Don't use IACK on CATS
+ *  16-Mar-1999	RMK	Added autodetect of ISA PICs
X  */
X #include <linux/config.h>
+#include <asm/hardware.h>
+#include <asm/dec21285.h>
+#include <asm/irq.h>
X 
-static void ebsa285_mask_irq(unsigned int irq)
+/*
+ * Footbridge IRQ translation table
+ *  Converts from our IRQ numbers into FootBridge masks
+ */
+static int dc21285_irq_mask[] = {
+	IRQ_MASK_UART_RX,	/*  0 */
+	IRQ_MASK_UART_TX,	/*  1 */
+	IRQ_MASK_TIMER1,	/*  2 */
+	IRQ_MASK_TIMER2,	/*  3 */
+	IRQ_MASK_TIMER3,	/*  4 */
+	IRQ_MASK_IN0,		/*  5 */
+	IRQ_MASK_IN1,		/*  6 */
+	IRQ_MASK_IN2,		/*  7 */
+	IRQ_MASK_IN3,		/*  8 */
+	IRQ_MASK_DOORBELLHOST,	/*  9 */
+	IRQ_MASK_DMA1,		/* 10 */
+	IRQ_MASK_DMA2,		/* 11 */
+	IRQ_MASK_PCI,		/* 12 */
+	IRQ_MASK_SDRAMPARITY,	/* 13 */
+	IRQ_MASK_I2OINPOST,	/* 14 */
+	IRQ_MASK_PCI_ERR	/* 15 */
+};
+
+static int isa_irq = -1;
+
+static inline int fixup_irq(unsigned int irq)
+{
+#ifdef CONFIG_HOST_FOOTBRIDGE
+	if (irq == isa_irq)
+		irq = *(unsigned char *)PCIIACK_BASE;
+#endif
+
+	return irq;
+}
+
+static void dc21285_mask_irq(unsigned int irq)
X {
-	*CSR_IRQ_DISABLE = 1 << irq;
+	*CSR_IRQ_DISABLE = dc21285_irq_mask[irq & 15];
X }
X 
-static void ebsa285_unmask_irq(unsigned int irq)
+static void dc21285_unmask_irq(unsigned int irq)
X {
-	*CSR_IRQ_ENABLE = 1 << irq;
+	*CSR_IRQ_ENABLE = dc21285_irq_mask[irq & 15];
X }
X 
-#ifdef CONFIG_CATS
+static void isa_mask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
X 
-/*
- * This contains the irq mask for both 8259A irq controllers,
- */
-static unsigned int isa_irq_mask = 0xffff;
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+}
X 
-#define cached_21	(isa_irq_mask & 0xff)
-#define cached_A1	((isa_irq_mask >> 8) & 0xff)
+static void isa_mask_ack_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
X 
-#define update_8259(_irq)			\
-	if ((_irq) & 8)				\
-		outb(cached_A1, 0xa1);		\
-	else					\
-		outb(cached_21, 0x21);
-
-static void isa_interrupt(int irq, void *h, struct pt_regs *regs)
-{
-	asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
-	unsigned int irqbits = inb(0x20) | (inb(0xa0) << 8), irqnr = 0;
-	irqbits &= ~(1<<2);	/* don't try to service the cascade */
-	while (irqbits) {
-		if (irqbits & 1)
-			do_IRQ(32 + irqnr, regs);
-		irqbits >>= 1;
-		irqnr++;
-	}
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+	outb(0x20, PIC_LO);
X }
X 
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+static void isa_unmask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
+}
X 
-static struct irqaction irq_isa = 
-		{ isa_interrupt, SA_INTERRUPT, 0, "ISA PIC", NULL, NULL };
-static struct irqaction irq_cascade = 
-		{ no_action, 0, 0, "cascade", NULL, NULL };
-
-static void cats_mask_and_ack_isa_irq(unsigned int irq)
-{
-	isa_irq_mask |= (1 << (irq - 32));
-	update_8259(irq);
-	if (irq & 8) {
-		inb(0xA1);	/* DUMMY */
-		outb(cached_A1,0xA1);
-		outb(0x62,0x20);	/* Specific EOI to cascade */
-		outb(0x20,0xA0);
-	} else {
-		inb(0x21);	/* DUMMY */
-		outb(cached_21,0x21);
-		outb(0x20,0x20);
-	}
+static void isa_mask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
X }
X 
-static void cats_mask_isa_irq(unsigned int irq)
+static void isa_mask_ack_pic_hi_irq(unsigned int irq)
X {
-	isa_irq_mask |= (1 << (irq - 32));
-	update_8259(irq);
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
+	outb(0x62, PIC_LO);
+	outb(0x20, PIC_HI);
X }
X 
-static void cats_unmask_isa_irq(unsigned int irq)
+static void isa_unmask_pic_hi_irq(unsigned int irq)
X {
-	isa_irq_mask &= ~(1 << (irq - 32));
-	update_8259(irq);
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
X }
- 
-#endif 
+
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
X 
X static __inline__ void irq_init_irq(void)
X {
X 	int irq;
X 
+	/*
+	 * setup DC21285 IRQs
+	 */
X 	*CSR_IRQ_DISABLE = -1;
X 	*CSR_FIQ_DISABLE = -1;
X 
-	for (irq = 0; irq < NR_IRQS; irq++) {
+	for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(16); irq++) {
X 		irq_desc[irq].valid	= 1;
X 		irq_desc[irq].probe_ok	= 1;
-#ifdef CONFIG_CATS
-		if (machine_is_cats() && IRQ_IS_ISA(irq)) {
-			irq_desc[irq].mask_ack	= cats_mask_and_ack_isa_irq;
-			irq_desc[irq].mask	= cats_mask_isa_irq;
-			irq_desc[irq].unmask	= cats_unmask_isa_irq;
+		irq_desc[irq].mask_ack	= dc21285_mask_irq;
+		irq_desc[irq].mask	= dc21285_mask_irq;
+		irq_desc[irq].unmask	= dc21285_unmask_irq;
+	}
+
+	/*
+	 * Determine the ISA settings for
+	 * the machine we're running on.
+	 */
+	switch (machine_arch_type) {
+	default:
+		isa_irq = -1;
+		break;
+
+	case MACH_TYPE_EBSA285:
+		/* The following is dependent on which slot
+		 * you plug the Southbridge card into.  We
+		 * currently assume that you plug it into
+		 * the right-hand most slot.
+		 */
+		isa_irq = IRQ_PCI;
+		break;
+
+	case MACH_TYPE_CATS:
+		isa_irq = IRQ_IN2;
+		break;
+
+	case MACH_TYPE_NETWINDER:
+		isa_irq = IRQ_IN3;
+		break;
+	}
+
+	if (isa_irq != -1) {
+		/*
+		 * Setup, and then probe for an ISA PIC
+		 */
+		outb(0x11, PIC_LO);
+		outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
+		outb(0x04, PIC_MASK_LO);	/* Slave on Ch2		*/
+		outb(0x01, PIC_MASK_LO);	/* x86			*/
+		outb(0xf5, PIC_MASK_LO);	/* pattern: 11110101	*/
+
+		outb(0x11, PIC_HI);
+		outb(_ISA_IRQ(8), PIC_MASK_HI);	/* IRQ number		*/
+		outb(0x02, PIC_MASK_HI);	/* Slave on Ch1		*/
+		outb(0x01, PIC_MASK_HI);	/* x86			*/
+		outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
+
+//		outb(0x68, PIC_LO);		/* enable special mode	*/
+//		outb(0x68, PIC_HI);		/* enable special mode	*/
+		outb(0x0b, PIC_LO);
+		outb(0x0b, PIC_HI);
+
+		if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
+			outb(0xff, PIC_MASK_LO);/* mask all IRQs	*/
+			outb(0xff, PIC_MASK_HI);/* mask all IRQs	*/
X 		} else
-#endif
-		{
-			irq_desc[irq].mask_ack	= ebsa285_mask_irq;
-			irq_desc[irq].mask	= ebsa285_mask_irq;
-			irq_desc[irq].unmask	= ebsa285_unmask_irq;
-		}
+			isa_irq = -1;
X 	}
X 
-#ifdef CONFIG_CATS
-	if (machine_is_cats()) {
-		request_region(0x20, 2, "pic1");
-		request_region(0xa0, 2, "pic2");
-
-		/* set up master 8259 */
-		outb(0x11, 0x20);
-		outb(0, 0x21);
-		outb(1<<2, 0x21);
-		outb(0x1, 0x21);
-		outb(0xff, 0x21);
-		outb(0x68, 0x20);
-		outb(0xa, 0x20);
-		
-		/* set up slave 8259 */
-		outb(0x11, 0xa0);
-		outb(0, 0xa1);
-		outb(2, 0xa1);
-		outb(0x1, 0xa1);
-		outb(0xff, 0xa1);
-		outb(0x68, 0xa0);
-		outb(0xa, 0xa0);
+	if (isa_irq != -1) {
+		for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
+			irq_desc[irq].valid	= 1;
+			irq_desc[irq].probe_ok	= 1;
+			irq_desc[irq].mask_ack	= isa_mask_ack_pic_lo_irq;
+			irq_desc[irq].mask	= isa_mask_pic_lo_irq;
+			irq_desc[irq].unmask	= isa_unmask_pic_lo_irq;
+		}
+
+		for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
+			irq_desc[irq].valid	= 1;
+			irq_desc[irq].probe_ok	= 1;
+			irq_desc[irq].mask_ack	= isa_mask_ack_pic_hi_irq;
+			irq_desc[irq].mask	= isa_mask_pic_hi_irq;
+			irq_desc[irq].unmask	= isa_unmask_pic_hi_irq;
+		}
X 
-		setup_arm_irq(IRQ_ISA_PIC, &irq_isa);
+		request_region(PIC_LO, 2, "pic1");
+		request_region(PIC_HI, 2, "pic2");
X 		setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
+		setup_arm_irq(isa_irq, &irq_cascade);
X 	}
-#endif
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/irqs.h linux/include/asm-arm/arch-ebsa285/irqs.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/irqs.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-ebsa285/irqs.h	Sat May  8 11:06:57 1999
@@ -3,55 +3,85 @@
X  *
X  * Copyright (C) 1998 Russell King
X  * Copyright (C) 1998 Phil Blundell
+ *
+ * Changelog:
+ *  20-Jan-1998	RMK	Started merge of EBSA286, CATS and NetWinder
+ *  01-Feb-1999	PJB	ISA IRQs start at 0 not 16
X  */
X 
-#define NR_IRQS			48
+#define NR_IRQS			32
+#define NR_DC21285_IRQS		16
+
+#define _ISA_IRQ(x)		(0 + (x))
+#define _DC21285_IRQ(x)		(16 + (x))
X 
X /*
X  * This is a list of all interrupts that the 21285
- * can generate
+ * can generate and we handle.
X  */
-#define IRQ_RESERVED		0
-#define IRQ_SOFTIRQ		1
-#define IRQ_CONRX		2
-#define IRQ_CONTX		3
-#define IRQ_TIMER1		4
-#define IRQ_TIMER2		5
-#define IRQ_TIMER3		6
-#define IRQ_TIMER4		7
-#define IRQ_IN0			8
-#define IRQ_IN1			9
-#define IRQ_IN2			10
-#define IRQ_IN3			11
-#define IRQ_XCS0		12
-#define IRQ_XCS1		13
-#define IRQ_XCS2		14
-#define IRQ_DOORBELLHOST	15
-#define IRQ_DMA1		16
-#define IRQ_DMA2		17
-#define IRQ_PCI			18
-#define IRQ_BIST		22
-#define IRQ_SERR		23
-#define IRQ_SDRAMPARITY		24
-#define IRQ_I2OINPOST		25
-#define IRQ_DISCARDTIMER	27
-#define IRQ_PCIDATAPARITY	28
-#define IRQ_PCIMASTERABORT	29
-#define IRQ_PCITARGETABORT	30
-#define IRQ_PCIPARITY		31
-
-/* IRQs 32-47 are the 16 ISA interrupts on a CATS board.  */
-#define IRQ_ISA_PIC	IRQ_IN2
-#define IRQ_IS_ISA(_x)	(((_x) >= 32) && ((_x) <= 47))
-#define IRQ_ISA(_x)	((_x) + 0x20)
-#define IRQ_ISA_CASCADE		IRQ_ISA(2)
+#define IRQ_CONRX		_DC21285_IRQ(0)
+#define IRQ_CONTX		_DC21285_IRQ(1)
+#define IRQ_TIMER1		_DC21285_IRQ(2)
+#define IRQ_TIMER2		_DC21285_IRQ(3)
+#define IRQ_TIMER3		_DC21285_IRQ(4)
+#define IRQ_IN0			_DC21285_IRQ(5)
+#define IRQ_IN1			_DC21285_IRQ(6)
+#define IRQ_IN2			_DC21285_IRQ(7)
+#define IRQ_IN3			_DC21285_IRQ(8)
+#define IRQ_DOORBELLHOST	_DC21285_IRQ(9)
+#define IRQ_DMA1		_DC21285_IRQ(10)
+#define IRQ_DMA2		_DC21285_IRQ(11)
+#define IRQ_PCI			_DC21285_IRQ(12)
+#define IRQ_SDRAMPARITY		_DC21285_IRQ(13)
+#define IRQ_I2OINPOST		_DC21285_IRQ(14)
+#define IRQ_PCI_ERR		_DC21285_IRQ(15)
+
+#define IRQ_ISA_TIMER		_ISA_IRQ(0)
+#define IRQ_ISA_KEYBOARD	_ISA_IRQ(1)
+#define IRQ_ISA_CASCADE		_ISA_IRQ(2)
+#define IRQ_ISA_UART2		_ISA_IRQ(3)
+#define IRQ_ISA_UART		_ISA_IRQ(4)
+#define IRQ_ISA_FLOPPY		_ISA_IRQ(6)
+#define IRQ_ISA_PRINTER		_ISA_IRQ(7)
+#define IRQ_ISA_RTC_ALARM	_ISA_IRQ(8)
+#define IRQ_ISA_2		_ISA_IRQ(9)
+#define IRQ_ISA_PS2MOUSE	_ISA_IRQ(12)
+#define IRQ_ISA_HARDDISK1	_ISA_IRQ(14)
+#define IRQ_ISA_HARDDISK2	_ISA_IRQ(15)
+
+#define IRQ_MASK_UART_RX	(1 << 2)
+#define IRQ_MASK_UART_TX	(1 << 3)
+#define IRQ_MASK_TIMER1		(1 << 4)
+#define IRQ_MASK_TIMER2		(1 << 5)
+#define IRQ_MASK_TIMER3		(1 << 6)
+#define IRQ_MASK_IN0		(1 << 8)
+#define IRQ_MASK_IN1		(1 << 9)
+#define IRQ_MASK_IN2		(1 << 10)
+#define IRQ_MASK_IN3		(1 << 11)
+#define IRQ_MASK_DOORBELLHOST	(1 << 15)
+#define IRQ_MASK_DMA1		(1 << 16)
+#define IRQ_MASK_DMA2		(1 << 17)
+#define IRQ_MASK_PCI		(1 << 18)
+#define IRQ_MASK_SDRAMPARITY	(1 << 24)
+#define IRQ_MASK_I2OINPOST	(1 << 25)
+#define IRQ_MASK_PCI_ERR	((1 <<23) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31))
X 
X /*
- * Now map them to the Linux interrupts
+ * Netwinder interrupt allocations
X  */
-#define IRQ_TIMER		IRQ_TIMER1
-#define IRQ_FLOPPYDISK		IRQ_ISA(6)
-#define IRQ_HARDDISK		IRQ_ISA(14)
-#define IRQ_HARDDISK_SECONDARY	IRQ_ISA(15)
+#define IRQ_NETWINDER_ETHER10	IRQ_IN0
+#define IRQ_NETWINDER_ETHER100	IRQ_IN1
+#define IRQ_NETWINDER_VIDCOMP	IRQ_IN2
+#define IRQ_NETWINDER_PS2MOUSE	_ISA_IRQ(5)
+#define IRQ_NETWINDER_IR	_ISA_IRQ(6)
+#define IRQ_NETWINDER_BUTTON	_ISA_IRQ(10)
+#define IRQ_NETWINDER_VGA	_ISA_IRQ(11)
+#define IRQ_NETWINDER_SOUND	_ISA_IRQ(12)
+
+#undef RTC_IRQ
+#define RTC_IRQ		IRQ_ISA_RTC_ALARM
+#undef AUX_IRQ
+#define AUX_IRQ		(machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE)
+#define IRQ_FLOPPYDISK	IRQ_ISA_FLOPPY
X 
-#define irq_cannonicalize(_i)	(((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA(9) : _i)
+#define irq_cannonicalize(_i)	(((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA_2 : _i)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/keyboard.h linux/include/asm-arm/arch-ebsa285/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-ebsa285/keyboard.h	Sat May  8 11:06:57 1999
@@ -6,16 +6,10 @@
X  * (C) 1998 Russell King
X  * (C) 1998 Phil Blundell
X  */
-
-#include <linux/config.h>
X #include <asm/irq.h>
X #include <asm/system.h>
X 
-#define NR_SCANCODES 128
-
-#ifdef CONFIG_CATS
-
-#define KEYBOARD_IRQ		IRQ_ISA(1)
+extern int have_isa_bridge;
X 
X extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
X extern int pckbd_getkeycode(unsigned int scancode);
@@ -26,40 +20,52 @@
X extern void pckbd_init_hw(void);
X extern unsigned char pckbd_sysrq_xlate[128];
X 
-#define kbd_setkeycode			pckbd_setkeycode
-#define kbd_getkeycode			pckbd_getkeycode
-#define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
-		pckbd_translate(sc & 0x7f, kcp, rm);})
+#define KEYBOARD_IRQ			IRQ_ISA_KEYBOARD
X 
-#define kbd_unexpected_up		pckbd_unexpected_up
-#define kbd_leds			pckbd_leds
-#define kbd_init_hw()			\
-		do { if (machine_is_cats()) pckbd_init_hw(); } while (0)
-#define kbd_sysrq_xlate			pckbd_sysrq_xlate
-#define kbd_disable_irq()
-#define kbd_enable_irq()
+#define NR_SCANCODES 128
X 
-#define SYSRQ_KEY	0x54
+#define kbd_setkeycode(sc,kc)				\
+	({						\
+		int __ret;				\
+		if (have_isa_bridge)			\
+			__ret = pckbd_setkeycode(sc,kc);\
+		else					\
+			__ret = -EINVAL;		\
+		__ret;					\
+	})
+
+#define kbd_getkeycode(sc)				\
+	({						\
+		int __ret;				\
+		if (have_isa_bridge)			\
+			__ret = pckbd_getkeycode(sc);	\
+		else					\
+			__ret = -EINVAL;		\
+		__ret;					\
+	})
+
+#define kbd_translate(sc, kcp, rm)			\
+	({						\
+		pckbd_translate(sc, kcp, rm);		\
+	})
X 
-#else
+#define kbd_unexpected_up		pckbd_unexpected_up
X 
-/* Dummy keyboard definitions */
+#define kbd_leds(leds)					\
+	do {						\
+		if (have_isa_bridge)			\
+			pckbd_leds(leds);		\
+	} while (0)
+
+#define kbd_init_hw()					\
+	do {						\
+		if (have_isa_bridge)			\
+			pckbd_init_hw();		\
+	} while (0)
X 
-#define kbd_setkeycode(sc,kc)		(-EINVAL)
-#define kbd_getkeycode(sc)		(-EINVAL)
+#define kbd_sysrq_xlate			pckbd_sysrq_xlate
X 
-/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
- * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
- *            set to 0200 if scancode indicates release
- */
-#define kbd_translate(sc, kcp, ufp, rm)	(1)
-#define kbd_unexpected_up(kc)		(0200)
-#define kbd_leds(leds)
-#define kbd_init_hw()
-//#define kbd_sysrq_xlate			ps2kbd_sysrq_xlate
X #define kbd_disable_irq()
X #define kbd_enable_irq()
X 
-#define SYSRQ_KEY	13
-
-#endif
+#define SYSRQ_KEY	0x54
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/memory.h	Mon May 10 10:17:28 1999
@@ -0,0 +1,74 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/memory.h
+ *
+ * Copyright (c) 1996-1999 Russell King.
+ *
+ * Changelog:
+ *  20-Oct-1996	RMK	Created
+ *  31-Dec-1997	RMK	Fixed definitions to reduce warnings.
+ *  17-May-1998	DAG	Added __virt_to_bus and __bus_to_virt functions.
+ *  21-Nov-1998	RMK	Changed __virt_to_bus and __bus_to_virt to macros.
+ *  21-Mar-1999	RMK	Added PAGE_OFFSET for co285 architecture.
+ *			Renamed to memory.h
+ *			Moved PAGE_OFFSET and TASK_SIZE here
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+#include <linux/config.h>
+
+#if defined(CONFIG_HOST_FOOTBRIDGE)
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE		(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET		(0xc0000000UL)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	((x) - 0xe0000000)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	((x) + 0xe0000000)
+
+#elif defined(CONFIG_ADDIN_FOOTBRIDGE)
+
+#if defined(CONFIG_ARCH_CO285)
+
+/*
+ * Task size: 1.5GB
+ */
+#define TASK_SIZE		(0x60000000UL)
+
+/*
+ * Page offset: 1.5GB
+ */
+#define PAGE_OFFSET		(0x60000000UL)
+
+#else
+
+#error Add in your architecture here
+
+#endif
+
+#ifndef __ASSEMBLY__
+extern unsigned long __virt_to_bus(unsigned long);
+extern unsigned long __bus_to_virt(unsigned long);
+#endif
+
+#endif
+
+/*
+ * On Footbridge machines, the dram is contiguous.
+ * On Host Footbridge, these conversions are constant.
+ * On an add-in footbridge, these depend on register settings.
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((unsigned long)(ppage) + PAGE_OFFSET)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/mm-init.h linux/include/asm-arm/arch-ebsa285/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/mm-init.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/mmu.h linux/include/asm-arm/arch-ebsa285/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/mmu.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa285/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- *  17-05-1998	DAG	Added __virt_to_bus and __bus_to_virt functions.
- *  21-11-1998	RMK	Changed __virt_to_bus and __bus_to_virt to macros.
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-/*
- * On ebsa285, the dram is contiguous
- */
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET)
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((unsigned long)(ppage) + PAGE_OFFSET)
-
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	((x) - 0xe0000000)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	((x) + 0xe0000000)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/oldlatches.h linux/include/asm-arm/arch-ebsa285/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/oldlatches.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/processor.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/processor.h	Sat May  8 11:06:57 1999
@@ -1,12 +1,17 @@
X /*
X  * linux/include/asm-arm/arch-ebsa110/processor.h
X  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
X  */
X 
X #ifndef __ASM_ARCH_PROCESSOR_H
X #define __ASM_ARCH_PROCESSOR_H
X 
+#include <asm/arch/memory.h>
+
X /*
X  * Bus types
X  */
@@ -15,17 +20,9 @@
X #define MCA_bus 0
X #define MCA_bus__is_a_macro /* for versions in ksyms.c */
X 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
X /* This decides where the kernel will search for a free chunk of vm
X  * space during mmap's.
X  */
X #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/serial.h linux/include/asm-arm/arch-ebsa285/serial.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/serial.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/serial.h	Sat May  8 11:06:57 1999
@@ -10,8 +10,6 @@
X #ifndef __ASM_ARCH_SERIAL_H
X #define __ASM_ARCH_SERIAL_H
X 
-#include <linux/config.h>
-
X #include <asm/irq.h>
X 
X /*
@@ -23,13 +21,8 @@
X  */
X #define BASE_BAUD (1843200 / 16)
X 
-#ifdef CONFIG_CATS
-#define _SER_IRQ0	IRQ_ISA(4)
-#define _SER_IRQ1	IRQ_ISA(3)
-#else
-#define _SER_IRQ0	0
-#define _SER_IRQ1	0
-#endif
+#define _SER_IRQ0	IRQ_ISA_UART
+#define _SER_IRQ1	IRQ_ISA_UART2
X 
X #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/system.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/system.h	Sat May  8 11:06:57 1999
@@ -3,6 +3,8 @@
X  *
X  * Copyright (c) 1996,1997,1998 Russell King.
X  */
+#include <asm/dec21285.h>
+#include <asm/io.h>
X #include <asm/hardware.h>
X #include <asm/leds.h>
X 
@@ -16,14 +18,37 @@
X 		 mov	r0, #0x130
X 		 mcr	p15, 0, r0, c1, c0	@ MMU off
X 		 mcr	p15, 0, ip, c7, c7	@ flush caches
-		 mov	pc, lr");
+		 mov	pc, lr" : : : "cc");
X 	} else {
-		/* To reboot, we set up the 21285 watchdog and enable it.
-		 * We then wait for it to timeout.
-		 */
-		*CSR_TIMER4_LOAD = 0x8000;
-		*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
-		*CSR_SA110_CNTL |= 1 << 13;
+		if (machine_is_ebsa285() || machine_is_co285()) {
+			/* To reboot, we set up the 21285 watchdog and
+			 * enable it.  We then wait for it to timeout.
+			 */
+			*CSR_TIMER4_LOAD = 0x8000;
+			*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE |
+					   TIMER_CNTL_AUTORELOAD |
+					   TIMER_CNTL_DIV16;
+			*CSR_SA110_CNTL |= 1 << 13;
+		} else if (machine_is_netwinder()) {
+			/* open up the SuperIO chip
+			 */
+			outb(0x87, 0x370);
+			outb(0x87, 0x370);
+
+			/* aux function group 1 (logical device 7)
+			 */
+			outb(0x07, 0x370);
+			outb(0x07, 0x371);
+
+			/* set GP16 for WD-TIMER output
+			 */
+			outb(0xe6, 0x370);
+			outb(0x00, 0x371);
+
+			/* set a RED LED and toggle WD_TIMER for rebooting
+			 */
+			outb(0xc4, 0x338);
+		}
X 	}
X }
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/time.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/time.h	Sat May  8 11:06:57 1999
@@ -10,116 +10,346 @@
X  *  21-Mar-1998	RMK	Created
X  *  27-Aug-1998	PJB	CATS support
X  *  28-Dec-1998	APH	Made leds optional
+ *  20-Jan-1999	RMK	Started merge of EBSA285, CATS and NetWinder
+ *  16-Mar-1999	RMK	More support for EBSA285-like machines with RTCs in
X  */
X 
-#define RTC_PORT(x)		(0x72+(x))
-#define RTC_ALWAYS_BCD		1
+#define RTC_PORT(x)		(rtc_base+(x))
+#define RTC_ALWAYS_BCD		0
X 
X #include <linux/config.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/dec21285.h>
X #include <asm/leds.h>
X #include <asm/system.h>
-#include <linux/mc146818rtc.h>
X 
-extern __inline__ unsigned long gettimeoffset (void)
+static int rtc_base;
+static unsigned long (*gettimeoffset)(void);
+static int (*set_rtc_mmss)(unsigned long nowtime);
+static long last_rtc_update = 0;	/* last time the cmos clock got updated */
+
+#ifdef CONFIG_LEDS
+static void do_leds(void)
+{
+	static unsigned int count = 50;
+	static int last_pid;
+
+	if (current->pid != last_pid) {
+		last_pid = current->pid;
+		if (last_pid)
+			leds_event(led_idle_end);
+		else
+			leds_event(led_idle_start);
+	}
+		
+	if (--count == 0) {
+		count = 50;
+		leds_event(led_timer);
+	}
+}
+#else
+#define do_leds()
+#endif
+
+#define mSEC_10_from_14 ((14318180 + 100) / 200)
+
+static unsigned long isa_gettimeoffset(void)
+{
+	int count;
+
+	static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off. 
+	 */
+	unsigned long jiffies_t;
+
+	/* timer count may underflow right here */
+	outb_p(0x00, 0x43);	/* latch the count ASAP */
+
+	count = inb_p(0x40);	/* read the latched count */
+
+	/*
+	 * We do this guaranteed double memory access instead of a _p 
+	 * postfix in the previous port access. Wheee, hackady hack
+	 */
+ 	jiffies_t = jiffies;
+
+	count |= inb_p(0x40) << 8;
+
+	/* Detect timer underflows.  If we haven't had a timer tick since 
+	   the last time we were called, and time is apparently going
+	   backwards, the counter must have wrapped during this routine. */
+	if ((jiffies_t == jiffies_p) && (count > count_p))
+		count -= (mSEC_10_from_14/6);
+	else
+		jiffies_p = jiffies_t;
+
+	count_p = count;
+
+	count = (((mSEC_10_from_14/6)-1) - count) * tick;
+	count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
+
+	return count;
+}
+
+static void isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (machine_is_netwinder())
+		do_leds();
+
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+}
+
+static struct irqaction isa_timer_irq = {
+	isa_timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+__initfunc(static unsigned long
+get_isa_cmos_time(void))
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int i;
+
+	// check to see if the RTC makes sense.....
+	if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
+		return mktime(1970, 1, 1, 0, 0, 0);
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+	/* read RTC exactly on falling edge of update flag */
+	for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+			break;
+
+	for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+			break;
+
+	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+		sec  = CMOS_READ(RTC_SECONDS);
+		min  = CMOS_READ(RTC_MINUTES);
+		hour = CMOS_READ(RTC_HOURS);
+		day  = CMOS_READ(RTC_DAY_OF_MONTH);
+		mon  = CMOS_READ(RTC_MONTH);
+		year = CMOS_READ(RTC_YEAR);
+	} while (sec != CMOS_READ(RTC_SECONDS));
+
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+static int
+set_isa_cmos_time(unsigned long nowtime)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned char save_control, save_freq_select;
+
+	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+	cmos_minutes = CMOS_READ(RTC_MINUTES);
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+		BCD_TO_BIN(cmos_minutes);
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;		/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+			BIN_TO_BCD(real_seconds);
+			BIN_TO_BCD(real_minutes);
+		}
+		CMOS_WRITE(real_seconds,RTC_SECONDS);
+		CMOS_WRITE(real_minutes,RTC_MINUTES);
+	} else
+		retval = -1;
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	return retval;
+}
+
+
+
+static unsigned long __ebsa285_text timer1_gettimeoffset (void)
X {
X 	unsigned long value = LATCH - *CSR_TIMER1_VALUE;
X 
X 	return (tick * value) / LATCH;
X }
X 
-extern __inline__ int reset_timer (void)
+static void __ebsa285_text timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
X {
X 	*CSR_TIMER1_CLR = 0;
X 
-#ifdef CONFIG_LEDS
-	/*
-	 * Do the LEDs thing on EBSA-285 hardware.
+	/* Do the LEDs things on non-CATS hardware.
X 	 */
-	if (!machine_is_cats()) {
-		static unsigned int count = 50;
-		static int last_pid;
-
-		if (current->pid != last_pid) {
-			last_pid = current->pid;
-			if (last_pid)
-				leds_event(led_idle_end);
-			else
-				leds_event(led_idle_start);
-		}
-		
-		if (--count == 0) {
-			count = 50;
-			leds_event(led_timer);
-		}
+	if (!machine_is_cats())
+		do_leds();
+
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 26'
echo 'File patch-2.2.8 is continued in part 27'
echo 27 > _shar_seq_.tmp
#!/bin/sh
# this is part 27 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 27; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
X 	}
-#endif
-	
-	return 1;
X }
X 
-/*
- * We don't have a RTC to update!
- */
-#define update_rtc()
+static struct irqaction __ebsa285_data timer1_irq = {
+	timer1_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+static int
+set_dummy_time(unsigned long secs)
+{
+	return 1;
+}
X 
X /*
X  * Set up timer interrupt, and return the current time in seconds.
X  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
X {
-	int year, mon, day, hour, min, sec;
+	switch(machine_arch_type) {
+	case MACH_TYPE_CO285:
+		/*
+		 * Add-in 21285s shouldn't access the RTC
+		 */
+		rtc_base = 0;
+		break;
X 
-	/*
-	 * Default the date to 1 Jan 1970 0:0:0
-	 */
-	year = 1970; mon = 1; day = 1;
-	hour = 0; min = 0; sec = 0;
+	default:
+		rtc_base = 0x70;
+		break;
+	}
+
+	if (rtc_base) {
+		int reg_d, reg_b;
+
+		reg_d = CMOS_READ(RTC_REG_D);
X 
-	*CSR_TIMER1_CLR  = 0;
-	*CSR_TIMER1_LOAD = LATCH;
-	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
-
-	if (machine_is_cats()) 
-	{
-		int i;
X 		/*
-		 * Read the real time from the Dallas chip.  (Code borrowed
-		 * from arch/i386/kernel/time.c).
+		 * make sure the divider is set
X 		 */
-		
-		/* The Linux interpretation of the CMOS clock register contents:
-		 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-		 * RTC registers show the second which has precisely just started.
-		 * Let's hope other operating systems interpret the RTC the same way.
+		CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_REG_A);
+
+		/*
+		 * Set control reg B
+		 *   (24 hour mode, update enabled)
X 		 */
+		reg_b = CMOS_READ(RTC_REG_B) & 0x7f;
+		reg_b |= 2;
+		CMOS_WRITE(reg_b, RTC_REG_B);
+
+		if ((CMOS_READ(RTC_REG_A) & 0x7f) == RTC_REF_CLCK_32KHZ &&
+		    CMOS_READ(RTC_REG_B) == reg_b) {
+
+			/*
+			 * Check the battery
+			 */
+			if ((reg_d & 0x80) == 0)
+				printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n");
+
+			xtime.tv_sec = get_isa_cmos_time();
+			set_rtc_mmss = set_isa_cmos_time;
+		} else
+			rtc_base = 0;
+	}
X 
-		/* read RTC exactly on falling edge of update flag */
-		for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-			if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-				break;
-		for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-			if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-				break;
-		do { /* Isn't this overkill ? UIP above should guarantee consistency */
-			sec = CMOS_READ(RTC_SECONDS);
-			min = CMOS_READ(RTC_MINUTES);
-			hour = CMOS_READ(RTC_HOURS);
-			day = CMOS_READ(RTC_DAY_OF_MONTH);
-			mon = CMOS_READ(RTC_MONTH);
-			year = CMOS_READ(RTC_YEAR);
-		} while (sec != CMOS_READ(RTC_SECONDS));
-		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-		{
-			BCD_TO_BIN(sec);
-			BCD_TO_BIN(min);
-			BCD_TO_BIN(hour);
-			BCD_TO_BIN(day);
-			BCD_TO_BIN(mon);
-			BCD_TO_BIN(year);
-		}
-		if ((year += 1900) < 1970)
-			year += 100;
+	if (!rtc_base) {
+		/*
+		 * Default the date to 1 Jan 1970 0:0:0
+		 */
+		xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
+		set_rtc_mmss = set_dummy_time;
X 	}
X 
-	return mktime(year, mon, day, hour, min, sec);
+	if (machine_is_ebsa285()) {
+		gettimeoffset = timer1_gettimeoffset;
+
+		*CSR_TIMER1_CLR  = 0;
+		*CSR_TIMER1_LOAD = LATCH;
+		*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+
+		setup_arm_irq(IRQ_TIMER1, &timer1_irq);
+	} else {
+		/* enable PIT timer */
+		/* set for periodic (4) and LSB/MSB write (0x30) */
+		outb(0x34, 0x43);
+		outb((mSEC_10_from_14/6) & 0xFF, 0x40);
+		outb((mSEC_10_from_14/6) >> 8, 0x40);
+
+		gettimeoffset = isa_gettimeoffset;
+
+		setup_arm_irq(IRQ_ISA_TIMER, &isa_timer_irq);
+	}
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/timex.h linux/include/asm-arm/arch-ebsa285/timex.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/timex.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/timex.h	Sat May  8 11:06:57 1999
@@ -7,8 +7,8 @@
X  */
X 
X /*
- * On the EBSA, the clock ticks at weird rates.
- * This is therefore not used to calculate the
- * divisor.
+ * On EBSA285 boards, the clock runs at 50MHz and is
+ * divided by a 4-bit prescaler.  Other boards use an
+ * ISA derived timer, and this is unused.
X  */
X #define CLOCK_TICK_RATE		(50000000 / 16)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/uncompress.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/uncompress.h	Sat May  8 11:06:57 1999
@@ -1,9 +1,12 @@
X /*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ * linux/include/asm-arm/arch-ebsa285/uncompress.h
X  *
X  * Copyright (C) 1996,1997,1998 Russell King
X  */
X 
+/*
+ * Note! This could cause problems on the NetWinder
+ */
X #define BASE 0x42000160
X 
X static __inline__ void putc(char c)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/a.out.h linux/include/asm-arm/arch-nexuspci/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/a.out.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-nexuspci/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
X /*
X * linux/include/asm-arm/arch-nexuspci/a.out.h
X  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
X  */
-
X #ifndef __ASM_ARCH_A_OUT_H
X #define __ASM_ARCH_A_OUT_H
X 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/hardware.h linux/include/asm-arm/arch-nexuspci/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/hardware.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-nexuspci/hardware.h	Sat May  8 11:06:57 1999
@@ -1,10 +1,12 @@
X /*
X  * linux/include/asm-arm/arch-nexuspci/hardware.h
X  *
- * Copyright (C) 1998 Philip Blundell
+ * Copyright (C) 1998-1999 Philip Blundell
X  *
X  * This file contains the hardware definitions of the Nexus PCI card.
X  */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
X 
X /*    Logical    Physical
X  * 0xfff00000	0x10000000	SCC2691 DUART
@@ -13,27 +15,17 @@
X  * 0xffc00000	0x60000000	PLX registers
X  * 0xfe000000	0x70000000	PCI I/O
X  */
- 
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-
-#define HAS_PCIO
-#define PCIO_BASE		0xfe000000
X 
X /*
X  * Mapping areas
X  */
-#define IO_BASE			0xfe000000
+#define PCIO_BASE		0xfe000000
+#define FLUSH_BASE		0xdf000000
X 
X /*
X  * RAM definitions
X  */
X #define RAM_BASE		0x40000000
-#define KERNTOPHYS(a)		((unsigned long)(&a))
X #define FLUSH_BASE_PHYS		0x40000000
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/irq.h linux/include/asm-arm/arch-nexuspci/irq.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/irq.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-nexuspci/irq.h	Sat May  8 11:06:57 1999
@@ -9,6 +9,8 @@
X 
X #include <asm/io.h>
X 
+#define fixup_irq(x) (x)
+
X #define INTCONT		0xffe00000
X 
X extern unsigned long soft_irq_mask;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/memory.h linux/include/asm-arm/arch-nexuspci/memory.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-nexuspci/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/memory.h
+ *
+ * Copyright (c) 1997, 1998 Philip Blundell.
+ * Copyright (c) 1999 Russell King
+ *
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+
+/*
+ * On NexusPCI, the DRAM is contiguous
+ */
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x40000000)
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x40000000)
+#define __virt_to_phys__is_a_macro
+#define __phys_to_virt__is_a_macro
+
+/*
+ * On the PCI bus the DRAM appears at address 0
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/mm-init.h linux/include/asm-arm/arch-nexuspci/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/mm-init.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-nexuspci/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/mmap.h
- *
- * Copyright (C) 1998 Philip Blundell
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/mmu.h linux/include/asm-arm/arch-nexuspci/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/mmu.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-nexuspci/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/mmu.h
- *
- * Copyright (c) 1997, 1998 Philip Blundell.
- *
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-/*
- * On NexusPCI, the DRAM is contiguous
- */
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x40000000)
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x40000000)
-#define __virt_to_phys__is_a_macro
-#define __phys_to_virt__is_a_macro
-
-/*
- * On the PCI bus the DRAM appears at address 0
- */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/processor.h linux/include/asm-arm/arch-nexuspci/processor.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/processor.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-nexuspci/processor.h	Sat May  8 11:06:57 1999
@@ -1,13 +1,18 @@
X /*
- * linux/include/asm-arm/arch-ebsa110/processor.h
+ * linux/include/asm-arm/arch-nexuspci/processor.h
X  *  from linux/include/asm-arm/arch-ebsa110/processor.h
X  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
X  */
X 
X #ifndef __ASM_ARCH_PROCESSOR_H
X #define __ASM_ARCH_PROCESSOR_H
X 
+#include <asm/arch/memory.h>
+
X /*
X  * Bus types
X  */
@@ -16,17 +21,9 @@
X #define MCA_bus 0
X #define MCA_bus__is_a_macro /* for versions in ksyms.c */
X 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
X /* This decides where the kernel will search for a free chunk of vm
X  * space during mmap's.
X  */
X #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/time.h linux/include/asm-arm/arch-nexuspci/time.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/time.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-nexuspci/time.h	Sat May  8 11:06:57 1999
@@ -17,37 +17,53 @@
X 	return 0;
X }
X 
-extern __inline__ int reset_timer (void)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
X {
X 	static int count = 50;
+
X 	writeb(0x90, UART_BASE + 8);
-	if (--count == 0)
- {
+
+	if (--count == 0) {
X 		static int state = 1;
X 		state ^= 1;
X 		writeb(0x1a + state, INTCONT);
X 		count = 50;
X 	}
+
X 	readb(UART_BASE + 0x14);
X 	readb(UART_BASE + 0x14);
X 	readb(UART_BASE + 0x14);
X 	readb(UART_BASE + 0x14);
X 	readb(UART_BASE + 0x14);
X 	readb(UART_BASE + 0x14);
-	return 1;
+
+	do_timer(regs);	
X }
X 
-extern __inline__ unsigned long setup_timer (void)
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+extern __inline__ void setup_timer(void)
X {
X 	int tick = 3686400 / 16 / 2 / 100;
+
X 	writeb(tick & 0xff, UART_BASE + 0x1c);
X 	writeb(tick >> 8, UART_BASE + 0x18);
X 	writeb(0x80, UART_BASE + 8);
X 	writeb(0x10, UART_BASE + 0x14);
+
X 	/*
X 	 * Default the date to 1 Jan 1970 0:0:0
X 	 * You will have to run a time daemon to set the
X 	 * clock correctly at bootup
X 	 */
-	return mktime(1970, 1, 1, 0, 0, 0);
+	xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
+
+	setup_arm_irq(IRQ_TIMER, &timerirq);
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/a.out.h linux/include/asm-arm/arch-rpc/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/a.out.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
X /*
X * linux/include/asm-arm/arch-rpc/a.out.h
X  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
X  */
-
X #ifndef __ASM_ARCH_A_OUT_H
X #define __ASM_ARCH_A_OUT_H
X 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/hardware.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/hardware.h	Sat May  8 11:06:57 1999
@@ -1,19 +1,19 @@
X /*
X  * linux/include/asm-arm/arch-rpc/hardware.h
X  *
- * Copyright (C) 1996 Russell King.
+ * Copyright (C) 1996-1999 Russell King.
X  *
X * This file contains the hardware definitions of the RiscPC series machines.
X  */
-
X #ifndef __ASM_ARCH_HARDWARE_H
X #define __ASM_ARCH_HARDWARE_H
X 
+#include <asm/arch/memory.h>
+
X /*
X  * What hardware must be present
X  */
X #define HAS_IOMD
-#include <asm/iomd.h>
X #define HAS_VIDC20
X 
X /* Hardware addresses of major areas.
@@ -26,7 +26,7 @@
X 
X #define EASI_SIZE		0x08000000	/* EASI I/O */
X #define EASI_START		0x08000000
-#define EASI_BASE		0xe8000000
+#define EASI_BASE		0xe5000000
X 
X #define IO_START		0x03000000	/* I/O */
X #define IO_SIZE			0x01000000
@@ -38,6 +38,8 @@
X #define SCREEN1_END		0xd8000000
X #define SCREEN1_BASE		0xd0000000
X 
+#define FLUSH_BASE		0xdf000000
+
X 
X #ifndef __ASSEMBLER__
X 
@@ -47,8 +49,9 @@
X #define IO_VIDC_AUDIO_BASE	0x80140000
X #define IO_VIDC_BASE		0x80100000
X #define IO_IOMD_BASE		0x80080000
+#define IOC_BASE		0x80080000
X 
-#define IO_EC_EASI_BASE		0x82000000
+#define IO_EC_EASI_BASE		0x81400000
X #define IO_EC_IOC4_BASE		0x8009c000
X #define IO_EC_IOC_BASE		0x80090000
X #define IO_EC_MEMC8_BASE	0x8000ac00
@@ -59,7 +62,6 @@
X  */
X #define EXPMASK_BASE		((volatile unsigned char *)0xe0360000)
X #define IOEB_BASE		((volatile unsigned char *)0xe0350050)
-#define IOC_BASE		((volatile unsigned char *)0xe0200000)
X #define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0xe002a000)
X #define PCIO_BASE		0xe0010000
X 
@@ -67,23 +69,19 @@
X  * Offsets from RAM base
X  */
X #define PARAMS_OFFSET		0x0100
-#define KERNEL_OFFSET		0x8000
X 
X /*
X  * RAM definitions
X  */
-#define MAPTOPHYS(x)		(x)
-#define KERNTOPHYS(x)		((unsigned long)(&x))
X #define GET_MEMORY_END(p)	(PAGE_OFFSET + p->u1.s.page_size * \
X 						(p->u1.s.pages_in_bank[0] + \
X 						 p->u1.s.pages_in_bank[1] + \
X 						 p->u1.s.pages_in_bank[2] + \
X 						 p->u1.s.pages_in_bank[3]))
X 
-#define KERNEL_BASE		(PAGE_OFFSET + KERNEL_OFFSET)
X #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
X #define Z_PARAMS_BASE		(RAM_START + PARAMS_OFFSET)
-#define SAFE_ADDR		0x00000000	/* ROM */
+#define FLUSH_BASE_PHYS		0x00000000	/* ROM */
X 
X #else
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/irq.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-rpc/irq.h	Sat May  8 11:06:57 1999
@@ -7,6 +7,9 @@
X  *   10-10-1996	RMK	Brought up to date with arch-sa110eval
X  *   22-08-1998	RMK	Restructured IRQ routines
X  */
+#include <asm/iomd.h>
+
+#define fixup_irq(x) (x)
X 
X static void rpc_mask_irq_ack_a(unsigned int irq)
X {
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/keyboard.h linux/include/asm-arm/arch-rpc/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-rpc/keyboard.h	Sat May  8 11:06:57 1999
@@ -10,7 +10,6 @@
X 
X #define NR_SCANCODES 128
X 
-extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
X extern void ps2kbd_leds(unsigned char leds);
X extern void ps2kbd_init_hw(void);
X extern unsigned char ps2kbd_sysrq_xlate[NR_SCANCODES];
@@ -18,15 +17,7 @@
X #define kbd_setkeycode(sc,kc)		(-EINVAL)
X #define kbd_getkeycode(sc)		(-EINVAL)
X 
-/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
- * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
- *            set to 0200 if scancode indicates release
- */
-#ifdef NEW_KEYBOARD
-#define kbd_translate(sc, kcp, ufp, rm)	ps2kbd_translate(sc, kcp, ufp)
-#else
-#define kbd_translate(sc, kcp, rm) ({ unsigned int up_flag; ps2kbd_translate(sc, kcp, &up_flag); })
-#endif
+#define kbd_translate(sc, kcp, rm)	({ *(kcp) = (sc); 1; })
X #define kbd_unexpected_up(kc)		(0200)
X #define kbd_leds(leds)			ps2kbd_leds(leds)
X #define kbd_init_hw()			ps2kbd_init_hw()
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/memory.h linux/include/asm-arm/arch-rpc/memory.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-arm/arch-rpc/memory.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ *
+ * Changelog:
+ *  20-Oct-1996	RMK	Created
+ *  31-Dec-1997	RMK	Fixed definitions to reduce warnings
+ *  11-Jan-1998	RMK	Uninlined to reduce hits on cache
+ *  08-Feb-1998	RMK	Added __virt_to_bus and __bus_to_virt
+ *  21-Mar-1999	RMK	Renamed to memory.h
+ * RMK Added TASK_SIZE and PAGE_OFFSET
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+
+#ifndef __ASSEMBLY__
+extern unsigned long __virt_to_phys(unsigned long vpage);
+extern unsigned long __phys_to_virt(unsigned long ppage);
+#endif
+
+/*
+ * These are exactly the same on the RiscPC as the
+ * physical memory view.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/mmu.h linux/include/asm-arm/arch-rpc/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/mmu.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-rpc/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,27 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- *  11-01-1998	RMK	Uninlined to reduce hits on cache
- *  08-02-1998	RMK	Added __virt_to_bus and __bus_to_virt
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-extern unsigned long __virt_to_phys(unsigned long vpage);
-extern unsigned long __phys_to_virt(unsigned long ppage);
-
-/*
- * These are exactly the same on the RiscPC as the
- * physical memory view.
- */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x) __phys_to_virt(x)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/oldlatches.h linux/include/asm-arm/arch-rpc/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/oldlatches.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/processor.h linux/include/asm-arm/arch-rpc/processor.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/processor.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/processor.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,18 @@
X /*
X  * linux/include/asm-arm/arch-rpc/processor.h
X  *
- * Copyright (c) 1996 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
X  *
X  * Changelog:
- *  10-09-1996	RMK	Created
+ *  10-Sep-1996	RMK	Created
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
X  */
X 
X #ifndef __ASM_ARCH_PROCESSOR_H
X #define __ASM_ARCH_PROCESSOR_H
X 
+#include <asm/arch/memory.h>
+
X /*
X  * Bus types
X  */
@@ -18,17 +21,9 @@
X #define MCA_bus 0
X #define MCA_bus__is_a_macro /* for versions in ksyms.c */
X 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
X /* This decides where the kernel will search for a free chunk of vm
X  * space during mmap's.
X  */
X #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/system.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/system.h	Sat May  8 11:06:57 1999
@@ -6,7 +6,7 @@
X #ifndef __ASM_ARCH_SYSTEM_H
X #define __ASM_ARCH_SYSTEM_H
X 
-#include <asm/proc-fns.h>
+#include <asm/iomd.h>
X 
X #define arch_reset(mode) {						\
X 	extern void ecard_reset (int card);				\
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/time.h linux/include/asm-arm/arch-rpc/time.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/time.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/time.h	Sat May  8 11:06:57 1999
@@ -8,6 +8,9 @@
X  *  10-Oct-1996	RMK	Brought up to date with arch-sa110eval
X  *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
X  */
+#include <asm/iomd.h>
+
+static long last_rtc_update = 0;	/* last time the cmos clock got updated */
X 
X extern __inline__ unsigned long gettimeoffset (void)
X {
@@ -51,46 +54,148 @@
X 	return offset;
X }
X 
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
+extern int iic_control(unsigned char, int, char *, int);
X 
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
+	/*FIXME:
+	 * This doesn't seem to work.  Does RISC OS
+	 * actually use the RTC year?  It doesn't
+	 * seem to.  In that case, how does it update
+	 * the CMOS year?
+	 */
+	/*year += (buf[3] >> 6) & 3;*/
+
+	/*
+	 * The RTC combines years with date and weekday
+	 * with month.  We need to mask off this extra
+	 * information before converting the date to
+	 * binary.
+	 */
+	buf[4] &= 0x1f;
+	buf[3] &= 0x3f;
+printk("Year %4d mon %02X day %02X hour %02X min %02X sec %02X\n", year, buf[4], buf[3], buf[2], buf[1], buf[0]);
X 	outb(LATCH & 255, IOMD_T0LTCHL);
X 	outb(LATCH >> 8, IOMD_T0LTCHH);
X 	outb(0, IOMD_T0GO);
X 
-	iic_control (0xa0, 0xc0, buf, 1);
-	year = buf[0];
-	if ((year += 1900) < 1970)
-		year += 100;
-
-	iic_control (0xa0, 2, buf, 5);
-	mon  = buf[4] & 0x1f;
-	day  = buf[3] & 0x3f;
-	hour = buf[2];
-	min  = buf[1];
-	sec  = buf[0];
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(sec);
+	xtime.tv_sec = get_rtc_time();
X 
-	return mktime(year, mon, day, hour, min, sec);
+	setup_arm_irq(IRQ_TIMER, &timerirq);
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/uncompress.h linux/include/asm-arm/arch-rpc/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/uncompress.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-rpc/uncompress.h	Sat May  8 11:06:57 1999
@@ -5,7 +5,6 @@
X  */
X #define VIDMEM ((char *)SCREEN_START)
X  
-#include "../arch/arm/drivers/char/font.h"
X #include <asm/hardware.h>
X #include <asm/io.h>
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/a.out.h linux/include/asm-arm/arch-vnc/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/a.out.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/dma.h linux/include/asm-arm/arch-vnc/dma.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/dma.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/dma.h	Wed Dec 31 16:00:00 1969
@@ -1,19 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/dma.h
- *
- * Architecture DMA routes
- *
- * Copyright (C) 1997.1998 Russell King
- */
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-/*
- * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
- */
-#define MAX_DMA_ADDRESS		0xd0000000
-#define MAX_DMA_CHANNELS	8
-
-#endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/hardware.h linux/include/asm-arm/arch-vnc/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/hardware.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/hardware.h	Wed Dec 31 16:00:00 1969
@@ -1,74 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/hardware.h
- *
- * Copyright (C) 1998 Corel Computer/Russell King.
- *
- * This file contains the hardware definitions of the VNC.
- */
-
-/*    Logical    Physical
- * 0xffe00000	0x7c000000	PCI I/O space
- * 0xfe000000	0x42000000	CSR
- * 0xfd000000	0x78000000	Outbound write flush
- * 0xfc000000	0x79000000	PCI IACK/special space
- * 0xf9000000	0x7a000000	PCI Config type 1
- * 0xf8000000	0x7b000000	PCI Config type 0
- * 
- */
-
-#include <asm/dec21285.h>
-
-#define IO_BASE_ARM_CSR		0xfe000000
-#define PCI_IACK		0xfc000000
- 
-/* LEDs */
-#define XBUS_LEDS		((volatile unsigned char *)0xfff12000)
-#define XBUS_LED_AMBER		(1 << 0)
-#define XBUS_LED_GREEN		(1 << 1)
-#define XBUS_LED_RED		(1 << 2)
-#define XBUS_LED_TOGGLE		(1 << 8)
-
-/* PIC irq control */
-#define PIC_LO			0x20
-#define PIC_MASK_LO		0x21
-#define PIC_HI			0xA0
-#define PIC_MASK_HI		0xA1
-
-#define IO_END			0xffffffff
-#define IO_BASE			0xe0000000
-#define IO_SIZE			(IO_END - IO_BASE)
-
-#define HAS_PCIO
-#define PCIO_BASE		0xffe00000
-
-#define KERNTOPHYS(a)		((unsigned long)(&a))
-
-//#define PARAMS_OFFSET		0x0100
-//#define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
-
-#define FLUSH_BASE_PHYS		0x50000000
-
-/* GPIO pins */
-#define GPIO_CCLK		0x800
-#define GPIO_DSCLK		0x400
-#define GPIO_E2CLK		0x200
-#define GPIO_IOLOAD		0x100
-#define GPIO_RED_LED		0x080
-#define GPIO_WDTIMER		0x040
-#define GPIO_DATA		0x020
-#define GPIO_IOCLK		0x010
-#define GPIO_DONE		0x008
-#define GPIO_FAN		0x004
-#define GPIO_GREEN_LED		0x002
-#define GPIO_RESET		0x001
-
-/* CPLD pins */
-#define CPLD_DSRESET		8
-#define CPLD_UNMUTE		2
-
-#ifndef __ASSEMBLY__
-extern void gpio_modify_op(int mask, int set);
-extern void gpio_modify_io(int mask, int in);
-extern int  gpio_read(void);
-extern void cpld_modify(int mask, int set);
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/ide.h linux/include/asm-arm/arch-vnc/ide.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/ide.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-vnc/ide.h	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/ide.h
- *
- * Copyright (c) 1998 Russell King
- *
- * Modifications:
- *  29-07-1998	RMK	Major re-work of IDE architecture specific code
- */
-#include <asm/irq.h>
-
-/*
- * Set up a hw structure for a specified data port, control port and IRQ.
- * This should follow whatever the default interface uses.
- */
-static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
-{
-	ide_ioreg_t reg = (ide_ioreg_t) data_port;
-	int i;
-
-	memset(hw, 0, sizeof(*hw));
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-	hw->irq = irq;
-}
-
-/*
- * This registers the standard ports for this architecture with the IDE
- * driver.
- */
-static __inline__ void
-ide_init_default_hwifs(void)
-{
-	hw_regs_t hw;
-
-	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
-	ide_register_hw(&hw, NULL);
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/io.h linux/include/asm-arm/arch-vnc/io.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/io.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/io.h	Wed Dec 31 16:00:00 1969
@@ -1,176 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/io.h
- *
- * Copyright (C) 1997,1998 Russell King
- *
- * Modifications:
- *  06-Dec-1997	RMK	Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef	ARCH_IO_DELAY
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-#define DECLARE_DYN_OUT(fnsuffix,instr,typ)					\
-extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
-{										\
-	__asm__ __volatile__(							\
-	"str%?" ##instr## "	%0, [%1, %2]		@ out"###fnsuffix	\
-	: 									\
-	: "r" (value), "r" (PCIO_BASE), typ (port));				\
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)					\
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
-{										\
-	unsigned long value;							\
-	__asm__ __volatile__(							\
-	"ldr%?" ##instr## "	%0, [%1, %2]		@ in"###fnsuffix	\
-	: "=&r" (value)								\
-	: "r" (PCIO_BASE), typ (port));						\
-	return (unsigned sz)value;						\
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)			\
-{										\
-	return (unsigned int)(PCIO_BASE + port);				\
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr,typ)	\
-	DECLARE_DYN_OUT(fnsuffix,instr,typ)	\
-	DECLARE_DYN_IN(sz,fnsuffix,instr,typ)
-
-DECLARE_IO(char,b,"b","Jr")
-DECLARE_IO(short,w,"h","r")
-DECLARE_IO(long,l,"","Jr")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_OUT
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
- "strb %0, [%1, %2] @ outbc" \
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inbc(port)								\
-({										\
-	unsigned char result;							\
-	__asm__ __volatile__(							\
- "ldrb %0, [%1, %2] @ inbc" \
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __outwc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
- "strh %0, [%1, %2] @ outwc" \
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "r" (port));				\
-})
-
-#define __inwc(port)								\
-({										\
-	unsigned short result;							\
-	__asm__ __volatile__(							\
- "ldrh %0, [%1, %2] @ inwc" \
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "r" (port));						\
-	result & 0xffff;							\
-})
-
-#define __outlc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
- "str %0, [%1, %2] @ outlc" \
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inlc(port)								\
-({										\
-	unsigned long result;							\
-	__asm__ __volatile__(							\
- "ldr %0, [%1, %2] @ inlc" \
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	addr = PCIO_BASE + port;						\
-	addr;									\
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)								\
-	(*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)								\
-	(*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)								\
-	(*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)								\
-	(*(volatile unsigned long *)(p))
-
-/*
- * This is not sufficient... (and it's a hack anyway)
- */
-static inline void writeb(unsigned char b, unsigned int addr)
-{
- *(volatile unsigned char *)(0xe0000000 + (addr)) = b;
-}
-
-static inline unsigned char readb(unsigned int addr)
-{
-	return *(volatile unsigned char *)(0xe0000000 + (addr));
-}
-
-static inline void writew(unsigned short b, unsigned int addr)
-{
-	*(volatile unsigned short *)(0xe0000000 + (addr)) = b;
-}
-
-static inline unsigned short readw(unsigned int addr)
-{
-	return *(volatile unsigned short *)(0xe0000000 + (addr));
-}
-
-static inline void writel(unsigned long b, unsigned int addr)
-{
-	*(volatile unsigned long *)(0xe0000000 + (addr)) = b;
-}
-
-static inline unsigned long readl(unsigned int addr)
-{
-	return *(volatile unsigned long *)(0xe0000000 + (addr));
-}
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/irq.h linux/include/asm-arm/arch-vnc/irq.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/irq.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-vnc/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,156 +0,0 @@
-/*
- * include/asm-arm/arch-vnc/irq.h
- *
- * Copyright (C) 1998 Russell King
- *
- * Changelog:
- *   22-08-1998	RMK	Restructured IRQ routines
- */
-
-#include <asm/dec21285.h>
-#include <asm/irq.h>
-
-/*
- * FootBridge IRQ translation table
- *  Converts form our IRQ numbers into FootBridge masks (defined in irqs.h)
- */
-static int fb_irq_mask[16] = {
-	0,
-	IRQ_MASK_SOFTIRQ,
-	IRQ_MASK_UART_DEBUG,
-	0,
-	IRQ_MASK_TIMER0,
-	IRQ_MASK_TIMER1,
-	IRQ_MASK_TIMER2,
-	IRQ_MASK_WATCHDOG,
-	IRQ_MASK_ETHER10,
-	IRQ_MASK_ETHER100,
-	IRQ_MASK_VIDCOMP,
-	IRQ_MASK_EXTERN_IRQ,
-	IRQ_MASK_DMA1,
-	0,
-	0,
-	IRQ_MASK_PCI_ERR
-};
-
-static void vnc_mask_csr_irq(unsigned int irq)
-{
-	*CSR_IRQ_DISABLE = fb_irq_mask[irq];
-}
-
-static void vnc_unmask_csr_irq(unsigned int irq)
-{
-	*CSR_IRQ_ENABLE = fb_irq_mask[irq];
-}
-
-static void vnc_mask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-}
-
-static void vnc_mask_ack_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-	outb(0x20, PIC_LO);
-}
-
-static void vnc_unmask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = ~(1 << (irq & 7));
-
-	outb(inb(PIC_MASK_LO) & mask, PIC_MASK_LO);
-}
-
-static void vnc_mask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-}
-
-static void vnc_mask_ack_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-	outb(0x62, PIC_LO);
-	outb(0x20, PIC_HI);
-}
-
-static void vnc_unmask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
-}
-
-static void no_action(int irq, void *dev_id, struct pt_regs *regs)
-{
-}
-
-static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
-
-static __inline__ void irq_init_irq(void)
-{
-	unsigned int irq;
-
-	outb(0x11, PIC_LO);
-	outb(0x10, PIC_MASK_LO);
-	outb(0x04, PIC_MASK_LO);
-	outb(1, PIC_MASK_LO);
-
-	outb(0x11, PIC_HI);
-	outb(0x18, PIC_MASK_HI);
-	outb(0x02, PIC_MASK_HI);
-	outb(1, PIC_MASK_HI);
-
-	*CSR_IRQ_DISABLE = ~IRQ_MASK_EXTERN_IRQ;
-	*CSR_IRQ_ENABLE  = IRQ_MASK_EXTERN_IRQ;
-	*CSR_FIQ_DISABLE = -1;
-
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-
-		if (irq < 16) {
-			irq_desc[irq].mask_ack	= vnc_mask_csr_irq;
-			irq_desc[irq].mask	= vnc_mask_csr_irq;
-			irq_desc[irq].unmask	= vnc_unmask_csr_irq;
-		} else if (irq < 24) {
-irq_desc[irq].probe_ok = 0;
-			irq_desc[irq].mask_ack	= vnc_mask_ack_pic_lo_irq;
-			irq_desc[irq].mask	= vnc_mask_pic_lo_irq;
-			irq_desc[irq].unmask	= vnc_unmask_pic_lo_irq;
-		} else {
-irq_desc[irq].probe_ok = 0;
-			irq_desc[irq].mask_ack	= vnc_mask_ack_pic_hi_irq;
-			irq_desc[irq].mask	= vnc_mask_pic_hi_irq;
-			irq_desc[irq].unmask	= vnc_unmask_pic_hi_irq;
-		}
-	}
-
-	irq_desc[0].probe_ok = 0;
-	irq_desc[IRQ_SOFTIRQ].probe_ok = 0;
-	irq_desc[IRQ_CONRX].probe_ok = 0;
-	irq_desc[IRQ_CONTX].probe_ok = 0;
-	irq_desc[IRQ_TIMER0].probe_ok = 0;
-	irq_desc[IRQ_TIMER1].probe_ok = 0;
-	irq_desc[IRQ_TIMER2].probe_ok = 0;
-	irq_desc[IRQ_WATCHDOG].probe_ok = 0;
-	irq_desc[IRQ_DMA1].probe_ok = 0;
-	irq_desc[13].probe_ok = 0;
-	irq_desc[14].probe_ok = 0;
-	irq_desc[IRQ_PCI_ERR].probe_ok = 0;
-	irq_desc[IRQ_PIC_HI].probe_ok = 0;
-	irq_desc[29].probe_ok = 0;
-	irq_desc[31].probe_ok = 0;
-
-	outb(0xff, PIC_MASK_LO);
-	outb(0xff, PIC_MASK_HI);
-
-	setup_arm_irq(IRQ_PIC_HI, &irq_cascade);
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/irqs.h linux/include/asm-arm/arch-vnc/irqs.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/irqs.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/irqs.h	Wed Dec 31 16:00:00 1969
@@ -1,67 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/irqs.h
- *
- * Copyright (C) 1998 Russell King
- */
-
-#define NR_IRQS			32
-
-/*
- * This is a list of all interrupts that the 21285
- * can generate
- */
-#define IRQ_SOFTIRQ		1	/* from FB.1 */
-#define IRQ_CONRX		2	/* from FB.2 */
-#define IRQ_CONTX		3	/* from FB.3 */
-#define IRQ_TIMER0		4	/* from FB.4 */
-#define IRQ_TIMER1		5	/* from FB.5 */
-#define IRQ_TIMER2		6	/* from FB.6 */
-#define IRQ_WATCHDOG		7	/* from FB.7 */
-#define IRQ_ETHER10		8	/* from FB.8 */
-#define IRQ_ETHER100		9	/* from FB.9 */
-#define IRQ_VIDCOMP		10	/* from FB.10 */
-#define IRQ_EXTERN_IRQ		11	/* from FB.11: chain to IDE irq's */
-#define IRQ_DMA1		12	/* from future */
-#define IRQ_PCI_ERR		15	/* from FB.[28:31] */
-
-#define IRQ_TIMER4		16	/* from 553.0 */
-#define IRQ_KEYBOARD		17	/* from 553.1 */
-#define IRQ_PIC_HI		18	/* from 533.2: chained to 553.[8:15] */
-#define IRQ_UART2		19	/* from 553.3 */
-#define IRQ_UART		20	/* from 553.4 */
-#define IRQ_MOUSE		21	/* from 553.5 */
-#define IRQ_UART_IR		22	/* from 553.6 */
-#define IRQ_PRINTER		23	/* from 553.7 */
-#define IRQ_RTC_ALARM		24	/* from 553.8 */
-#define IRQ_POWERLOW		26	/* from 553.10 */
-#define IRQ_VGA			27	/* from 553.11 */
-#define IRQ_SOUND		28	/* from 553.12 */
-#define IRQ_HARDDISK		30	/* from 553.14 */
-
-/* These defines handle the translation from the above FB #defines
- * into physical bits for the FootBridge IRQ registers
- */
-#define IRQ_MASK_SOFTIRQ	0x00000002
-#define IRQ_MASK_UART_DEBUG	0x0000000C
-#define IRQ_MASK_TIMER0		0x00000010
-#define IRQ_MASK_TIMER1		0x00000020
-#define IRQ_MASK_TIMER2		0x00000040
-#define IRQ_MASK_WATCHDOG	0x00000080
-#define IRQ_MASK_ETHER10	0x00000100
-#define IRQ_MASK_ETHER100	0x00000200
-#define IRQ_MASK_VIDCOMP	0x00000400
-#define IRQ_MASK_EXTERN_IRQ	0x00000800
-#define IRQ_MASK_DMA1		0x00030000
-#define IRQ_MASK_PCI_ERR	0xf8800000
-
-/*
- * Now map them to the Linux interrupts
- */
-#undef IRQ_TIMER
-#define IRQ_TIMER		IRQ_TIMER0
-#undef RTC_IRQ
-#define RTC_IRQ			IRQ_RTC_ALARM
-#undef AUX_IRQ
-#define AUX_IRQ			IRQ_MOUSE
-
-#define irq_cannonicalize(i)	(i)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/keyboard.h linux/include/asm-arm/arch-vnc/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-vnc/keyboard.h	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/keyboard.h
- *
- * Keyboard driver definitions for VNC architecture
- *
- * (C) 1998 Russell King
- */
-
-#include <asm/irq.h>
-
-#define NR_SCANCODES 128
-
-#define KEYBOARD_IRQ			IRQ_KEYBOARD
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
-
-#define kbd_setkeycode			pckbd_setkeycode
-#define kbd_getkeycode			pckbd_getkeycode
-#define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
-		pckbd_translate(sc & 0x7f, kcp, rm);})
-
-#define kbd_unexpected_up		pckbd_unexpected_up
-#define kbd_leds			pckbd_leds
-#define kbd_init_hw() pckbd_init_hw()
-#define kbd_sysrq_xlate			pckbd_sysrq_xlate
-#define kbd_disable_irq()
-#define kbd_enable_irq()
-
-#define SYSRQ_KEY 0x54
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/mm-init.h linux/include/asm-arm/arch-vnc/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/mm-init.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/mmu.h linux/include/asm-arm/arch-vnc/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/mmu.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-vnc/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-/*
- * On ebsa, the dram is contiguous
- */
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
-
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	(x - 0xe0000000)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	(x + 0xe0000000)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/oldlatches.h linux/include/asm-arm/arch-vnc/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/oldlatches.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/param.h linux/include/asm-arm/arch-vnc/param.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/param.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-vnc/param.h	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/param.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1998 Philip Blundell
- */
-
-#define HZ 100
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/processor.h linux/include/asm-arm/arch-vnc/processor.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/processor.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/processor.h	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/processor.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/serial.h linux/include/asm-arm/arch-vnc/serial.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/serial.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/serial.h	Wed Dec 31 16:00:00 1969
@@ -1,43 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  15-10-1996	RMK	Created
- *  03-05-1998	RMK	Modified for Corel Video NC
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-#include <asm/irq.h>
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define SERIAL_PORT_DFNS \
-	{ 0, BASE_BAUD, 0x3F8, IRQ_UART	, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, IRQ_UART2, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS3 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS }, 	/* ttyS4 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS5 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS6 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS7 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS8 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS9 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS10 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS11 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS12 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS13 */
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/shmparam.h linux/include/asm-arm/arch-vnc/shmparam.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/shmparam.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/system.h linux/include/asm-arm/arch-vnc/system.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/system.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/system.h	Wed Dec 31 16:00:00 1969
@@ -1,37 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/system.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- * Copyright (c) 1998 Corel Computer Corp.
- */
-#include <asm/hardware.h>
-#include <asm/dec21285.h>
-#include <asm/leds.h>
-#include <asm/io.h>
-
-extern __inline__ void arch_reset(char mode)
-{
-	cli();
-
-	/* open up the SuperIO chip
-	 */
-	outb(0x87, 0x370);
-	outb(0x87, 0x370);
-
-	/* aux function group 1 (Logical Device 7)
-	 */
-	outb(0x07, 0x370);
-	outb(0x07, 0x371);
-
-	/* set GP16 for WD-TIMER output
-	 */
-	outb(0xE6, 0x370);
-	outb(0x00, 0x371);
-
-	/* set a RED LED and toggle WD_TIMER for rebooting...
-	 */
-	outb(0xC4, 0x338);
-}
-
-#define arch_start_idle()	leds_event(led_idle_start)
-#define arch_end_idle()		leds_event(led_idle_end)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/time.h linux/include/asm-arm/arch-vnc/time.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/time.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/time.h	Wed Dec 31 16:00:00 1969
@@ -1,232 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/time.h
- *
- * Copyright (c) 1997 Corel Computer Corp.
- * Slight modifications to bring in line with ebsa285 port.
- *  -- Russell King.
- *  Added LED driver (based on the ebsa285 code) - Alex Holden 28/12/98.
- */
-
-#include <linux/config.h>
-#include <linux/mc146818rtc.h>
-
-#include <asm/leds.h>
-#include <asm/system.h>
-
-#undef IRQ_TIMER
-#define IRQ_TIMER		IRQ_TIMER4
-
-#define mSEC_10_from_14 ((14318180 + 100) / 200)
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
-	int count;
-
-	static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
-	static unsigned long jiffies_p = 0;
-
-	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off. 
-	 */
-	unsigned long jiffies_t;
-
-	/* timer count may underflow right here */
-	outb_p(0x00, 0x43);	/* latch the count ASAP */
-
-	count = inb_p(0x40);	/* read the latched count */
-
-	/*
-	 * We do this guaranteed double memory access instead of a _p 
-	 * postfix in the previous port access. Wheee, hackady hack
-	 */
- 	jiffies_t = jiffies;
-
-	count |= inb_p(0x40) << 8;
-
-	/* Detect timer underflows.  If we haven't had a timer tick since 
-	   the last time we were called, and time is apparently going
-	   backwards, the counter must have wrapped during this routine. */
-	if ((jiffies_t == jiffies_p) && (count > count_p))
-		count -= (mSEC_10_from_14/6);
-	else
-		jiffies_p = jiffies_t;
-
-	count_p = count;
-
-	count = (((mSEC_10_from_14/6)-1) - count) * tick;
-	count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
-
-	return count;
-}
-
-extern __inline__ int reset_timer (void)
-{
-#ifdef CONFIG_LEDS
-	static unsigned int count = 50;
-	static int last_pid;
-
-	if (current->pid != last_pid) {
-		last_pid = current->pid;
-		if (last_pid)
-			leds_event(led_idle_end);
-		else
-			leds_event(led_idle_start);
-	}
-
-	if (--count == 0) {
-		count = 50;
-		leds_event(led_timer);
-	}
-#endif
-	return 1;
-}
-
-unsigned long set_rtc_mmss(unsigned long nowtime)
-{
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
-	unsigned char save_control, save_freq_select;
-
-	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-	cmos_minutes = CMOS_READ(RTC_MINUTES);
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-		BCD_TO_BIN(cmos_minutes);
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-		real_minutes += 30;		/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-			BIN_TO_BCD(real_seconds);
-			BIN_TO_BCD(real_minutes);
-		}
-		CMOS_WRITE(real_seconds,RTC_SECONDS);
-		CMOS_WRITE(real_minutes,RTC_MINUTES);
-	} else
-		retval = -1;
-
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_WRITE(save_control, RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
-	return retval;
-}
-
-/*
- * We don't have a RTC to update!
- */
-extern __inline__ void update_rtc(void)
-{
-	static long last_rtc_update = 0;	/* last time the cmos clock got updated */
-
-	/* If we have an externally synchronized linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec > 50000 - (tick >> 1) &&
-	    xtime.tv_usec < 50000 + (tick >> 1)) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
-}
-
-extern __inline__ unsigned long get_cmos_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int i;
-
-	// check to see if the RTC makes sense.....
-	if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
-		return mktime(1970, 1, 1, 0, 0, 0);
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-
-	for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		sec = CMOS_READ(RTC_SECONDS);
-		min = CMOS_READ(RTC_MINUTES);
-		hour = CMOS_READ(RTC_HOURS);
-		day = CMOS_READ(RTC_DAY_OF_MONTH);
-		mon = CMOS_READ(RTC_MONTH);
-		year = CMOS_READ(RTC_YEAR);
-	} while (sec != CMOS_READ(RTC_SECONDS));
-
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
-	}
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
-	unsigned int c;
-
-	/* Turn on the RTC */
-	outb(13, 0x70);
-	if ((inb(0x71) & 0x80) == 0)
-		printk("RTC: *** warning: CMOS battery bad\n");
-
-	outb(10, 0x70);		/* select control reg */
-	outb(32, 0x71);		/* make sure the divider is set */
-	outb(11, 0x70);		/* select other control reg */
-	c = inb(0x71) & 0xfb;	/* read it */
-	outb(11, 0x70);
-	outb(c | 2, 0x71);	/* turn on BCD counting and 24 hour clock mode */
-	
-	/* enable PIT timer */
-	/* set for periodic (4) and LSB/MSB write (0x30) */
-	outb(0x34, 0x43);
-	outb((mSEC_10_from_14/6) & 0xFF, 0x40);
-	outb((mSEC_10_from_14/6) >> 8, 0x40);
-
-	/*
-	 * Default the date to 1 Jan 1970 00:00:00
-	 * You will have to run a time daemon to set the
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 27'
echo 'File patch-2.2.8 is continued in part 28'
echo 28 > _shar_seq_.tmp
#!/bin/sh
# this is part 28 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 28; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
-	 * clock correctly at bootup
-	 */
-	return get_cmos_time();
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/timex.h linux/include/asm-arm/arch-vnc/timex.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/timex.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/timex.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/timex.h
- *
- * Corel Video NC architecture timex specifications
- *
- * Copyright (C) 1998 Corel Computer/Russell King
- */
-
-/*
- * On the VNC, the clock runs at 66MHz and is divided
- * by a 4-bit prescaler.
- */
-#define CLOCK_TICK_RATE		(66000000 / 16)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/uncompress.h linux/include/asm-arm/arch-vnc/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/uncompress.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-vnc/uncompress.h	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
-	__asm__ __volatile__("
-	ldrb	%0, [%2], #1
-	teq	%0, #0
-	beq	3f
-1:	strb	%0, [%3]
-2:	ldrb	%1, [%3, #0x14]
-	and	%1, %1, #0x60
-	teq	%1, #0x60
-	bne	2b
-	teq	%0, #'\n'
-	moveq	%0, #'\r'
-	beq	1b
-	ldrb	%0, [%2], #1
-	teq	%0, #0
-	bne	1b
-3:	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/dec21285.h linux/include/asm-arm/dec21285.h
--- v2.2.7/linux/include/asm-arm/dec21285.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/dec21285.h	Sat May  8 11:06:57 1999
@@ -15,17 +15,20 @@
X #define DC21285_PCI_MEM			0x80000000
X 
X #ifndef __ASSEMBLY__
-#define DC21285_IO(x)		((volatile unsigned long *)(0xfe000000+(x)))
+#include <asm/arch/hardware.h>
+#define DC21285_IO(x)		((volatile unsigned long *)(ARMCSR_BASE+(x)))
X #else
X #define DC21285_IO(x)		(x)
X #endif
X 
X #define CSR_PCICMD		DC21285_IO(0x0004)
+#define CSR_CLASSREV		DC21285_IO(0x0008)
X #define CSR_PCICACHELINESIZE	DC21285_IO(0x000c)
X #define CSR_PCICSRBASE		DC21285_IO(0x0010)
X #define CSR_PCICSRIOBASE	DC21285_IO(0x0014)
X #define CSR_PCISDRAMBASE	DC21285_IO(0x0018)
X #define CSR_PCIROMBASE		DC21285_IO(0x0030)
+#define CSR_ROMWRITEREG		DC21285_IO(0x0068)
X #define CSR_CSRBASEMASK		DC21285_IO(0x00f8)
X #define CSR_CSRBASEOFFSET	DC21285_IO(0x00fc)
X #define CSR_SDRAMBASEMASK	DC21285_IO(0x0100)
@@ -44,6 +47,33 @@
X #define CSR_I2O_OUTPOSTCOUNT	DC21285_IO(0x0134)
X #define CSR_I2O_INPOSTCOUNT	DC21285_IO(0x0138)
X #define CSR_SA110_CNTL		DC21285_IO(0x013c)
+#define SA110_CNTL_INITCMPLETE		(1 << 0)
+#define SA110_CNTL_ASSERTSERR		(1 << 1)
+#define SA110_CNTL_RXSERR		(1 << 3)
+#define SA110_CNTL_SA110DRAMPARITY	(1 << 4)
+#define SA110_CNTL_PCISDRAMPARITY	(1 << 5)
+#define SA110_CNTL_DMASDRAMPARITY	(1 << 6)
+#define SA110_CNTL_DISCARDTIMER		(1 << 8)
+#define SA110_CNTL_PCINRESET		(1 << 9)
+#define SA110_CNTL_I2O_256		(0 << 10)
+#define SA110_CNTL_I20_512		(1 << 10)
+#define SA110_CNTL_I2O_1024		(2 << 10)
+#define SA110_CNTL_I2O_2048		(3 << 10)
+#define SA110_CNTL_I2O_4096		(4 << 10)
+#define SA110_CNTL_I2O_8192		(5 << 10)
+#define SA110_CNTL_I2O_16384		(6 << 10)
+#define SA110_CNTL_I2O_32768		(7 << 10)
+#define SA110_CNTL_WATCHDOG		(1 << 13)
+#define SA110_CNTL_ROMWIDTH_UNDEF	(0 << 14)
+#define SA110_CNTL_ROMWIDTH_16		(1 << 14)
+#define SA110_CNTL_ROMWIDTH_32		(2 << 14)
+#define SA110_CNTL_ROMWIDTH_8		(3 << 14)
+#define SA110_CNTL_ROMACCESSTIME(x)	((x)<<16)
+#define SA110_CNTL_ROMBURSTTIME(x)	((x)<<20)
+#define SA110_CNTL_ROMTRISTATETIME(x)	((x)<<24)
+#define SA110_CNTL_XCSDIR(x)		((x)<<28)
+#define SA110_CNTL_PCICFN		(1 << 31)
+
X #define CSR_PCIADDR_EXTN	DC21285_IO(0x0140)
X #define CSR_PREFETCHMEMRANGE	DC21285_IO(0x0144)
X #define CSR_XBUS_CYCLE		DC21285_IO(0x0148)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h
--- v2.2.7/linux/include/asm-arm/dma.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/dma.h	Sat May  8 11:07:16 1999
@@ -6,20 +6,20 @@
X #include <linux/config.h>
X #include <linux/kernel.h>
X #include <asm/irq.h>
-#include <asm/system.h>
X #include <asm/spinlock.h>
X #include <asm/arch/dma.h>
X 
X /*
- * DMA modes - we have two, IN and OUT
+ * DMA modes
X  */
X typedef unsigned int dmamode_t;
X 
-#define DMA_MODE_MASK	1
+#define DMA_MODE_MASK	3
X 
-#define DMA_MODE_READ	0
-#define DMA_MODE_WRITE	1
-#define DMA_AUTOINIT	2
+#define DMA_MODE_READ	 0
+#define DMA_MODE_WRITE	 1
+#define DMA_MODE_CASCADE 2
+#define DMA_AUTOINIT	 4
X 
X typedef struct {
X 	unsigned long address;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/ecard.h linux/include/asm-arm/ecard.h
--- v2.2.7/linux/include/asm-arm/ecard.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/ecard.h	Sat May  8 11:06:57 1999
@@ -47,6 +47,9 @@
X #define MANU_ICS		0x003c
X #define PROD_ICS_IDE			0x00ae
X 
+#define MANU_ICS2		0x003d
+#define PROD_ICS2_IDE			0x00ae
+
X #define MANU_SERPORT		0x003f
X #define PROD_SERPORT_DSPORT		0x00b9
X 
@@ -76,7 +79,7 @@
X #define CONST const
X #endif
X 
-#define MAX_ECARDS	8
+#define MAX_ECARDS	9
X 
X typedef enum {				/* Cards address space		*/
X 	ECARD_IOC,
@@ -116,14 +119,18 @@
X typedef struct {			/* Card handler routines	*/
X 	void (*irqenable)(ecard_t *ec, int irqnr);
X 	void (*irqdisable)(ecard_t *ec, int irqnr);
+	int  (*irqpending)(ecard_t *ec);
X 	void (*fiqenable)(ecard_t *ec, int fiqnr);
X 	void (*fiqdisable)(ecard_t *ec, int fiqnr);
+	int  (*fiqpending)(ecard_t *ec);
X } expansioncard_ops_t;
X 
X /*
X  * This contains all the info needed on an expansion card
X  */
X struct expansion_card {
+	struct expansion_card  *next;
+
X 	/* Public data */
X 	volatile unsigned char *irqaddr;	/* address of IRQ register	*/
X 	volatile unsigned char *fiqaddr;	/* address of FIQ register	*/
@@ -135,10 +142,10 @@
X 	void			*fiq_data;	/* Data for use for FIQ by card	*/
X 	expansioncard_ops_t	*ops;		/* Enable/Disable Ops for card	*/
X 
-	CONST unsigned char	slot_no;	/* Slot number			*/
-	CONST unsigned char	dma;		/* DMA number (for request_dma)	*/
-	CONST unsigned char	irq;		/* IRQ number (for request_irq)	*/
-	CONST unsigned char	fiq;		/* FIQ number (for request_irq)	*/
+	CONST unsigned int	slot_no;	/* Slot number			*/
+	CONST unsigned int	dma;		/* DMA number (for request_dma)	*/
+	CONST unsigned int	irq;		/* IRQ number (for request_irq)	*/
+	CONST unsigned int	fiq;		/* FIQ number (for request_irq)	*/
X 	CONST card_type_t	type;		/* Type of card			*/
X 	CONST struct in_ecid	cid;		/* Card Identification		*/
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/fiq.h linux/include/asm-arm/fiq.h
--- v2.2.7/linux/include/asm-arm/fiq.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/fiq.h	Sat May  8 11:06:57 1999
@@ -30,5 +30,6 @@
X extern void release_fiq(struct fiq_handler *f);
X extern void set_fiq_handler(void *start, unsigned int length);
X extern void set_fiq_regs(struct pt_regs *regs);
+extern void get_fiq_regs(struct pt_regs *regs);
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/floppy.h linux/include/asm-arm/floppy.h
--- v2.2.7/linux/include/asm-arm/floppy.h	Tue Jun 23 10:01:26 1998
+++ linux/include/asm-arm/floppy.h	Sat May  8 11:06:57 1999
@@ -120,5 +120,20 @@
X #define FLOPPY_MOTOR_MASK 0xf0
X 
X #define CROSS_64KB(a,s) (0)
+
+/*
+ * This allows people to reverse the order of
+ * fd0 and fd1, in case their hardware is
+ * strangely connected (as some RiscPCs
+ * and A5000s seem to be).
+ */
+static void driveswap(int *ints, int dummy, int dummy2)
+{
+	floppy_selects[0][0] ^= floppy_selects[0][1];
+	floppy_selects[0][1] ^= floppy_selects[0][0];
+	floppy_selects[0][0] ^= floppy_selects[0][1];
+}
+
+#define EXTRA_FLOPPY_PARAMS ,{ "driveswap", &driveswap, NULL, 0, 0 }
X 	
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h
--- v2.2.7/linux/include/asm-arm/hardware.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/hardware.h	Sat May  8 11:06:57 1999
@@ -11,10 +11,6 @@
X 
X #include <asm/arch/hardware.h>
X 
-#ifndef FLUSH_BASE
-#define FLUSH_BASE	0xdf000000
-#endif
-
X #ifdef HAS_EXPMASK
X #ifndef __ASSEMBLER__
X #define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/init.h linux/include/asm-arm/init.h
--- v2.2.7/linux/include/asm-arm/init.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/init.h	Sat May  8 11:06:57 1999
@@ -5,7 +5,7 @@
X 
X /* C routines */
X 
-#ifdef CONFIG_TEXT_INIT_SECTION
+#ifdef CONFIG_TEXT_SECTIONS
X 
X #define __init __attribute__ ((__section__ (".text.init")))
X #define __initfunc(__arginit) \
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.2.7/linux/include/asm-arm/io.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/io.h	Sat May  8 11:06:57 1999
@@ -8,12 +8,35 @@
X  *			constant addresses and variable addresses.
X  *  04-Dec-1997	RMK	Moved a lot of this stuff to the new architecture
X  *			specific IO header files.
+ *  27-Mar-1999	PJB	Second parameter of memcpy_toio is const..
+ *  04-Apr-1999	PJB	Added check_signature.
X  */
X #ifndef __ASM_ARM_IO_H
X #define __ASM_ARM_IO_H
X 
+#ifdef __KERNEL__
+
+#ifndef NULL
+#define NULL	((void *) 0)
+#endif
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+/*
+ * String version of IO memory access ops:
+ */
+extern void _memcpy_fromio(void *, unsigned long, unsigned long);
+extern void _memcpy_toio(unsigned long, const void *, unsigned long);
+extern void _memset_io(unsigned long, int, unsigned long);
+
+#define memcpy_fromio(to,from,len)	_memcpy_fromio((to),(unsigned long)(from),(len))
+#define memcpy_toio(to,from,len)	_memcpy_toio((unsigned long)(to),(from),(len))
+#define memset_io(addr,c,len)		_memset_io((unsigned long)(addr),(c),(len))
+
+#endif
+
X #include <asm/hardware.h>
-#include <asm/arch/mmu.h>
+#include <asm/arch/memory.h>
X #include <asm/arch/io.h>
X #include <asm/proc/io.h>
X 
@@ -168,25 +191,43 @@
X 
X #endif
X 
-#undef ARCH_IO_DELAY
-#undef ARCH_IO_CONSTANT
+#ifndef ARCH_READWRITE
X 
-#ifdef __KERNEL__
+/* for panic */
+#include <linux/kernel.h>
X 
-extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+#define readb(p)	(panic("readb called, but not implemented"),0)
+#define readw(p)	(panic("readw called, but not implemented"),0)
+#define readl(p)	(panic("readl called, but not implemented"),0)
+#define writeb(v,p)	panic("writeb called, but not implemented")
+#define writew(v,p)	panic("writew called, but not implemented")
+#define writel(v,p)	panic("writel called, but not implemented")
X 
-/*
- * String version of IO memory access ops:
- */
-extern void _memcpy_fromio(void *, unsigned long, unsigned long);
-extern void _memcpy_toio(unsigned long, void *, unsigned long);
-extern void _memset_io(unsigned long, int, unsigned long);
+#endif
X 
-#define memcpy_fromio(to,from,len)	_memcpy_fromio((to),(unsigned long)(from),(len))
-#define memcpy_toio(to,from,len)	_memcpy_toio((unsigned long)(to),(from),(len))
-#define memset_io(addr,c,len)		_memset_io((unsigned long)(addr),(c),(len))
+/*
+ * This isn't especially architecture dependent so it seems like it
+ * might as well go here as anywhere.
+ */
+static inline int check_signature(unsigned long io_addr,
+                                  const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
X 
-#endif
+#undef ARCH_READWRITE
+#undef ARCH_IO_DELAY
+#undef ARCH_IO_CONSTANT
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/ioc.h linux/include/asm-arm/ioc.h
--- v2.2.7/linux/include/asm-arm/ioc.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/ioc.h	Sat May  8 11:06:57 1999
@@ -3,6 +3,8 @@
X  * read/write.
X  */
X 
+#ifndef IOC_CONTROL
+
X #ifndef __ASSEMBLER__
X #define __IOC(offset)	(IOC_BASE + (offset >> 2))
X #else
@@ -54,3 +56,4 @@
X #define IOC_T3GO	__IOC(0x78)
X #define IOC_T3LATCH	__IOC(0x7c)
X 
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/iomd.h linux/include/asm-arm/iomd.h
--- v2.2.7/linux/include/asm-arm/iomd.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/iomd.h	Sat May  8 11:06:57 1999
@@ -125,6 +125,8 @@
X #define DMA_ST_OFL	4
X #define DMA_ST_INT	2
X #define DMA_ST_AB	1
+
+#ifndef IOC_CONTROL
X /*
X  * IOC compatability
X  */
@@ -155,6 +157,7 @@
X #define IOC_T1LTCHH	IOMD_T1LTCHH
X #define IOC_T1GO	IOMD_T1GO
X #define IOC_T1LATCH	IOMD_T1LATCH
+#endif
X 
X /*
X  * DMA (MEMC) compatability
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/irq.h linux/include/asm-arm/irq.h
--- v2.2.7/linux/include/asm-arm/irq.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/irq.h	Sat May  8 11:07:16 1999
@@ -16,8 +16,10 @@
X  * capability
X  */
X #ifndef NO_IRQ
-#define NO_IRQ	255
+#define NO_IRQ	((unsigned int)(-1))
X #endif
+
+#define disable_irq_nosync(i) disable_irq(i)
X 
X extern void disable_irq(unsigned int);
X extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/leds.h linux/include/asm-arm/leds.h
--- v2.2.7/linux/include/asm-arm/leds.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/leds.h	Sat May  8 11:06:57 1999
@@ -10,15 +10,32 @@
X #ifndef ASM_ARM_LEDS_H
X #define ASM_ARM_LEDS_H
X 
+#include <linux/config.h>
+
X typedef enum {
X 	led_idle_start,
X 	led_idle_end,
X 	led_timer,
X 	led_start,
-	led_stop
+	led_stop,
+	led_claim,		/* override idle & timer leds */
+	led_release,		/* restore idle & timer leds */
+	led_green_on,
+	led_green_off,
+	led_amber_on,
+	led_amber_off,
+	led_red_on,
+	led_red_off
X } led_event_t;
X 
X /* Use this routine to handle LEDs */
-extern void leds_event(led_event_t);
+
+#ifdef CONFIG_LEDS
+extern void (*leds_event)(led_event_t);
+#define set_leds_event(r)	leds_event = r
+#else
+#define leds_event(e)
+#define set_leds_event(r)
+#endif
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/memc.h linux/include/asm-arm/memc.h
--- v2.2.7/linux/include/asm-arm/memc.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/memc.h	Sat May  8 11:06:57 1999
@@ -4,6 +4,9 @@
X #define VDMA_START	1
X #define VDMA_END	2
X 
+#ifndef __ASSEMBLER__
+extern void memc_write(unsigned int reg, unsigned long val);
+
X #define video_set_dma(start,end,offset)				\
X do {								\
X 	memc_write (VDMA_START, (start >> 2));			\
@@ -11,3 +14,4 @@
X 	memc_write (VDMA_INIT, (offset >> 2));			\
X } while (0)
X 
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/mm-init.h linux/include/asm-arm/mm-init.h
--- v2.2.7/linux/include/asm-arm/mm-init.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,46 +0,0 @@
-/*
- * linux/include/asm-arm/mm-init.h
- *
- * Copyright (C) 1997,1998 Russell King
- *
- * Contained within are structures to describe how to set up the
- * initial memory map.  It includes both a processor-specific header
- * for parsing these structures, and an architecture-specific header
- * to fill out the structures.
- */
-#ifndef __ASM_MM_INIT_H
-#define __ASM_MM_INIT_H
-
-typedef enum {
-	// physical address is absolute
-	init_mem_map_absolute,
-	/* physical address is relative to start_mem
-	 *  as passed in paging_init
-	 */
-	init_mem_map_relative_start_mem
-} init_memmap_type_t;
-
-typedef struct {
-	init_memmap_type_t type;
-	unsigned long physical_address;
-	unsigned long virtual_address;
-	unsigned long size;
-} init_memmap_t;
-
-#define INIT_MEM_MAP_SENTINEL { init_mem_map_absolute, 0, 0, 0 }
-#define INIT_MEM_MAP_ABSOLUTE(p,l,s) { init_mem_map_absolute,p,l,s }
-#define INIT_MEM_MAP_RELATIVE(o,l,s) { init_mem_map_relative_start_mem,o,l,s }
-
-/*
- * Within this file, initialise an array of init_mem_map_t's
- * to describe your initial memory mapping structure.
- */
-#include <asm/arch/mm-init.h>
-
-/*
- * Contained within this file is code to read the array
- * of init_mem_map_t's created above.
- */
-#include <asm/proc/mm-init.h>
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/page.h linux/include/asm-arm/page.h
--- v2.2.7/linux/include/asm-arm/page.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/page.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,15 @@
X #ifndef _ASMARM_PAGE_H
X #define _ASMARM_PAGE_H
X 
-#include <asm/arch/mmu.h>
+#include <asm/arch/memory.h>
X #include <asm/proc/page.h>
X 
X #ifdef __KERNEL__
X 
X #define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
X #define free_user_page(page, addr)	free_page(addr)
-#define clear_page(page)	memzero((void *)(page), PAGE_SIZE)
-#define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+#define clear_page(page)		memzero((void *)(page), PAGE_SIZE)
+#define copy_page(to,from)		memcpy((void *)(to), (void *)(from), PAGE_SIZE)
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/posix_types.h linux/include/asm-arm/posix_types.h
--- v2.2.7/linux/include/asm-arm/posix_types.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/posix_types.h	Sat May  8 11:06:57 1999
@@ -45,6 +45,8 @@
X #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
X } __kernel_fsid_t;
X 
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
X #undef	__FD_SET
X #define __FD_SET(fd, fdsetp) \
X 		(((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31)))
@@ -60,5 +62,7 @@
X #undef	__FD_ZERO
X #define __FD_ZERO(fdsetp) \
X 		(memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp)))
+
+#endif
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/mm-init-flat.h linux/include/asm-arm/proc-armo/mm-init-flat.h
--- v2.2.7/linux/include/asm-arm/proc-armo/mm-init-flat.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/mm-init-flat.h	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/mmap.h
- *
- * Copyright (C) 1996 Russell King
- *
- * This contains the code to setup the memory map on an ARM2/ARM250/ARM3
- * machine. This is both processor & architecture specific, and requires
- * some more work to get it to fit into our separate processor and
- * architecture structure.
- */
-
-static unsigned long phys_screen_end;
-int page_nr;
-
-#define setup_processor_functions()
-
-/*
- * This routine needs more work to make it dynamically release/allocate mem!
- */
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-	static int updated = 0;
-	unsigned long address = SCREEN_START, i;
-	pgd_t *pg_dir;
-	pmd_t *pm_dir;
-	pte_t *pt_entry;
-
-	if (updated)
-		return 0;
-	updated = update;
-
-	pg_dir = swapper_pg_dir + (SCREEN1_BASE >> PGDIR_SHIFT);
-	pm_dir = pmd_offset(pg_dir, SCREEN1_BASE);
-	pt_entry = pte_offset(pm_dir, SCREEN1_BASE);
-
-	for (i = SCREEN1_BASE; i < SCREEN1_END; i += PAGE_SIZE) {
-		if (i >= log_start) {
-			*pt_entry = mk_pte(address, __pgprot(_PAGE_PRESENT));
-			address += PAGE_SIZE;
-		} else
-			*pt_entry = mk_pte(0, __pgprot(0));
-		pt_entry++;
-	}
-	phys_screen_end = address;
-	if (update)
-		flush_tlb_all ();
-	return kmem;
-}
-
-static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem)
-{
-	unsigned long address;
-	unsigned int spi;
-
-	page_nr = MAP_NR(end_mem);
-
-	/* Allocate zero page */
-	address = PAGE_OFFSET + 480*1024;
-	for (spi = 0; spi < 32768 >> PAGE_SHIFT; spi++) {
-		pgd_val(swapper_pg_dir[spi]) = pte_val(mk_pte(address, PAGE_READONLY));
-		address += PAGE_SIZE;
-	}
-
-	while (spi < (PAGE_OFFSET >> PGDIR_SHIFT))
-		pgd_val(swapper_pg_dir[spi++]) = 0;
-
-	map_screen_mem (SCREEN1_END - 480*1024, 0, 0);
-	return start_mem;
-}
-
-static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
-{
-	unsigned long smem = PAGE_ALIGN(*start_mem);
-
-	while (smem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-		smem += PAGE_SIZE;
-	}
-
-	for (smem = phys_screen_end; smem < SCREEN2_END; smem += PAGE_SIZE)
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/mm-init.h linux/include/asm-arm/proc-armo/mm-init.h
--- v2.2.7/linux/include/asm-arm/proc-armo/mm-init.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/proc-armo/mm-init.h	Sat May  8 11:06:57 1999
@@ -8,8 +8,8 @@
X  * some more work to get it to fit into our separate processor and
X  * architecture structure.
X  */
-extern unsigned long phys_screen_end;
-extern unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update);
+#include <asm/arch/memory.h>
+
X int page_nr;
X 
X #define setup_processor_functions()
@@ -20,10 +20,11 @@
X 	set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep));
X }
X 
-static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem)
+static inline unsigned long
+setup_pagetables(unsigned long start_mem, unsigned long end_mem)
X {
X 	unsigned int i;
-	union {unsigned long l; pte_t *pte; } u;
+	union { unsigned long l; pte_t *pte; } u;
X 
X 	page_nr = MAP_NR(end_mem);
X 
@@ -37,14 +38,11 @@
X 	for (i = 1; i < PTRS_PER_PGD; i++)
X 		pgd_val(swapper_pg_dir[i]) = 0;
X 
-	/* now map screen mem in */
-	phys_screen_end = SCREEN2_END;
-	map_screen_mem (SCREEN1_END - 480*1024, 0, 0);
-
X 	return start_mem;
X }
X 
-static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
+static inline void
+mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
X {
X 	unsigned long smem;
X 
@@ -54,7 +52,4 @@
X 		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
X 		smem += PAGE_SIZE;
X 	}
-
-	for (smem = phys_screen_end; smem < SCREEN2_END; smem += PAGE_SIZE)
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/page.h linux/include/asm-arm/proc-armo/page.h
--- v2.2.7/linux/include/asm-arm/proc-armo/page.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/proc-armo/page.h	Sat May  8 11:06:57 1999
@@ -68,7 +68,6 @@
X #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
X 
X /* This handles the memory map.. */
-#define PAGE_OFFSET		0x02000000
X #define MAP_NR(addr)		(((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
X 
X #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/pgtable-flat.h linux/include/asm-arm/proc-armo/pgtable-flat.h
--- v2.2.7/linux/include/asm-arm/proc-armo/pgtable-flat.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/pgtable-flat.h	Wed Dec 31 16:00:00 1969
@@ -1,307 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/pgtable.h
- *
- * Copyright (C) 1995, 1996 Russell King
- */
-#ifndef __ASM_PROC_PGTABLE_H
-#define __ASM_PROC_PGTABLE_H
-
-#include <asm/arch/mmu.h>
-
-#define LIBRARY_TEXT_START 0x0c000000
-
-/*
- * Cache flushing...
- */
-#define flush_cache_all()			do { } while (0)
-#define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm,start,end)		do { } while (0)
-#define flush_cache_page(vma,vmaddr)		do { } while (0)
-#define flush_page_to_ram(page)			do { } while (0)
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
- */
-
-#define flush_tlb() flush_tlb_mm(current->mm)
-
-extern __inline__ void flush_tlb_all(void)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		processor.u.armv2._update_map(p);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	processor.u.armv2._remap_memc (current);
-}
-
-extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		if (p->mm == mm)
-			processor.u.armv2._update_map(p);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	if (current->mm == mm)
-		processor.u.armv2._remap_memc (current);
-}
-
-#define flush_tlb_range(mm, start, end) flush_tlb_mm(mm)
-#define flush_tlb_page(vma, vmaddr) flush_tlb_mm(vma->vm_mm)
-
-#define __flush_entry_to_ram(entry)
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define PMD_SHIFT       PAGE_SHIFT
-#define PMD_SIZE        (1UL << PMD_SHIFT)
-#define PMD_MASK        (~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT     PAGE_SHIFT
-#define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK      (~(PGDIR_SIZE-1))
-
-/*
- * entries per page directory level: the arm3 is one-level, so
- * we don't really have any PMD or PTE directory physically.
- */
-#define PTRS_PER_PTE    1
-#define PTRS_PER_PMD    1
-#define PTRS_PER_PGD    1024
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_START	0x01a00000
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-
-#define _PAGE_PRESENT   0x001
-#define _PAGE_RW        0x002
-#define _PAGE_USER      0x004
-#define _PAGE_PCD       0x010
-#define _PAGE_ACCESSED  0x020
-#define _PAGE_DIRTY     0x040
-
-#define _PAGE_TABLE     (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-
-#define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-
-/*
- * The arm can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
- */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
-#define __P010  PAGE_COPY
-#define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
-#define __P110  PAGE_COPY
-#define __P111  PAGE_COPY
-
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
-#define __S010  PAGE_SHARED
-#define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
-#define __S110  PAGE_SHARED
-#define __S111  PAGE_SHARED
-
-#undef TEST_VERIFY_AREA
-
-/*
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern unsigned long *empty_zero_page;
-
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
-
-/* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR			(sizeof(unsigned long))
-#define BITS_PER_PTR                    (8*BYTES_PER_PTR)
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK                        (~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2                 2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* to set the page-dir */
-#define SET_PAGE_DIR(tsk,pgdir)						\
-do {									\
-	tsk->tss.memmap = (unsigned long)pgdir;				\
-	processor.u.armv2._update_map(tsk);				\
-	if ((tsk) == current)						\
-		processor.u.armv2._remap_memc (current);		\
-} while (0)
-
-extern unsigned long physical_start;
-extern unsigned long physical_end;
-
-extern inline int pte_none(pte_t pte)           { return !pte_val(pte); }
-extern inline int pte_present(pte_t pte)        { return pte_val(pte) & _PAGE_PRESENT; }
-extern inline void pte_clear(pte_t *ptep)       { pte_val(*ptep) = 0; }
-
-extern inline int pmd_none(pmd_t pmd)           { return 0; }
-extern inline int pmd_bad(pmd_t pmd)            { return 0; }
-extern inline int pmd_present(pmd_t pmd)        { return 1; }
-extern inline void pmd_clear(pmd_t * pmdp)      { }
-
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-extern inline int pgd_none(pgd_t pgd)           { return 0; }
-extern inline int pgd_bad(pgd_t pgd)            { return 0; }
-extern inline int pgd_present(pgd_t pgd)        { return 1; }
-extern inline void pgd_clear(pgd_t * pgdp)      { }
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-extern inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_RW; }
-extern inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_DIRTY; }
-extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
-#define pte_cacheable(pte) 1
-
-extern inline pte_t pte_nocache(pte_t pte)	{ return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)        { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)       { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)       { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)      { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = virt_to_phys(page) | pgprot_val(pgprot); return pte; }
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline unsigned long pte_page(pte_t pte)
-{ return phys_to_virt(pte_val(pte) & PAGE_MASK); }
-
-extern inline unsigned long pmd_page(pmd_t pmd)
-{ return phys_to_virt(pmd_val(pmd) & PAGE_MASK); }
-
-/* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-        return mm->pgd + (address >> PGDIR_SHIFT);
-}
-
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, address) ((pmd_t *)(dir))
-
-/* Find an entry in the third-level page table.. */
-#define pte_offset(dir, address) ((pte_t *)(dir))
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-extern inline void pte_free_kernel(pte_t * pte)
-{
-	pte_val(*pte) = 0;
-}
-
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
-	return (pte_t *) pmd;
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free_kernel(pmdp)
-#define pmd_alloc_kernel(pgd,address) ((pmd_t *)(pgd))
-
-#define pte_free(ptep)
-#define pte_alloc(pmd,address) ((pte_t *)(pmd))
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free(pmd)
-#define pmd_alloc(pgd,address) ((pmd_t *)(pgd))
-
-extern inline void pgd_free(pgd_t * pgd)
-{
-	extern void kfree(void *);
-	kfree((void *)pgd);
-}
-
-extern inline pgd_t * pgd_alloc(void)
-{
-	pgd_t *pgd;
-	extern void *kmalloc(unsigned int, int);
-	
-	pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
-	if (pgd)
-		memset(pgd, 0, PTRS_PER_PGD * BYTES_PER_PTR);
-	return pgd;
-}
-
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-#define update_mmu_cache(vma,address,pte) processor.u.armv2._update_mmu_cache(vma,address,pte)
-
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) <<  8))
-
-#endif /* __ASM_PROC_PAGE_H */
-
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.2.7/linux/include/asm-arm/proc-armo/pgtable.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/proc-armo/pgtable.h	Sat May  8 11:06:57 1999
@@ -7,9 +7,9 @@
X #ifndef __ASM_PROC_PGTABLE_H
X #define __ASM_PROC_PGTABLE_H
X 
-#include <asm/arch/mmu.h>
+#include <linux/config.h>
X #include <linux/slab.h>
-#include <asm/arch/processor.h>		/* For TASK_SIZE */
+#include <asm/arch/memory.h>		/* For TASK_SIZE */
X 
X #define LIBRARY_TEXT_START 0x0c000000
X 
@@ -280,13 +280,17 @@
X 	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
X }
X 
-extern __inline__ pmd_t mk_pmd (pte_t *ptep)
+extern __inline__ pmd_t mk_pmd(pte_t *ptep)
X {
X 	pmd_t pmd;
X 	pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_TABLE;
X 	return pmd;
X }
X 
+/* these are aliases for the above function */
+#define mk_user_pmd(ptep)   mk_pmd(ptep)
+#define mk_kernel_pmd(ptep) mk_pmd(ptep)
+
X #define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd))
X 
X extern __inline__ unsigned long pmd_page(pmd_t pmd)
@@ -319,6 +323,7 @@
X  */
X 
X #ifndef __SMP__
+#ifndef CONFIG_NO_PGT_CACHE
X extern struct pgtable_cache_struct {
X 	unsigned long *pgd_cache;
X 	unsigned long *pte_cache;
@@ -329,13 +334,16 @@
X #define pte_quicklist (quicklists.pte_cache)
X #define pgd_quicklist (quicklists.pgd_cache)
X #define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#endif
X 
X #else
X #error Pgtable caches have to be per-CPU, so that no locking is needed.
X #endif
X 
X extern pgd_t *get_pgd_slow(void);
+extern void free_table(void *table);
X 
+#ifndef CONFIG_NO_PGT_CACHE
X extern __inline__ pgd_t *get_pgd_fast(void)
X {
X 	unsigned long *ret;
@@ -355,14 +363,17 @@
X 	pgd_quicklist = (unsigned long *) pgd;
X 	pgtable_cache_size++;
X }
+#endif
X 
+/* keep this as an inline so we get type checking */
X extern __inline__ void free_pgd_slow(pgd_t *pgd)
X {
-	kfree(pgd);
+	free_table((void *)pgd);
X }
X 
X extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
X 
+#ifndef CONFIG_NO_PGT_CACHE
X extern __inline__ pte_t *get_pte_fast(void)
X {
X 	unsigned long *ret;
@@ -381,10 +392,12 @@
X 	pte_quicklist = (unsigned long *) pte;
X 	pgtable_cache_size++;
X }
+#endif
X 
+/* keep this as an inline so we get type checking */
X extern __inline__ void free_pte_slow(pte_t *pte)
X {
-	kfree(pte);
+	free_table((void *)pte);
X }
X 
X /* We don't use pmd cache, so this is a dummy routine */
@@ -404,6 +417,26 @@
X extern void __bad_pmd(pmd_t *pmd);
X extern void __bad_pmd_kernel(pmd_t *pmd);
X 
+#ifdef CONFIG_NO_PGT_CACHE
+#define pte_free_kernel(pte)    free_pte_slow(pte)
+#define pte_free(pte)           free_pte_slow(pte)
+#define pgd_free(pgd)           free_pgd_slow(pgd)
+#define pgd_alloc()             get_pgd_slow()
+
+extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+
+	if (pmd_none (*pmd)) {
+		return get_pte_slow(pmd, address);
+	}
+	if (pmd_bad (*pmd)) {
+		__bad_pmd(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+#else
X #define pte_free_kernel(pte)    free_pte_fast(pte)
X #define pte_free(pte)           free_pte_fast(pte)
X #define pgd_free(pgd)           free_pgd_fast(pgd)
@@ -427,6 +460,7 @@
X 	}
X 	return (pte_t *) pmd_page(*pmd) + address;
X }
+#endif
X 
X /*
X  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -448,7 +482,6 @@
X extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
X {
X 	struct task_struct * p;
-	pgd_t *pgd;
X 
X 	read_lock(&tasklist_lock);
X 	for_each_task(p) {
@@ -457,8 +490,14 @@
X 		*pgd_offset(p->mm,address) = entry;
X 	}
X 	read_unlock(&tasklist_lock);
-	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
-		pgd[address >> PGDIR_SHIFT] = entry;
+#ifndef CONFIG_NO_PGT_CACHE
+	{
+		pgd_t *pgd;
+		for (pgd = (pgd_t *)pgd_quicklist; pgd;
+		     pgd = (pgd_t *)*(unsigned long *)pgd)
+			pgd[address >> PGDIR_SHIFT] = entry;
+	}
+#endif
X }
X 
X extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h
--- v2.2.7/linux/include/asm-arm/proc-armo/processor.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/proc-armo/processor.h	Sat May  8 11:06:57 1999
@@ -14,8 +14,6 @@
X #ifndef __ASM_PROC_PROCESSOR_H
X #define __ASM_PROC_PROCESSOR_H
X 
-#ifdef __KERNEL__
-
X #include <asm/assembler.h>
X #include <linux/string.h>
X 
@@ -32,6 +30,8 @@
X 	unsigned long pc;
X };
X 
+#define INIT_CSS (struct context_save_struct){ 0, 0, 0, 0, 0, 0, 0, SVC26_MODE }
+
X typedef struct {
X 	void (*put_byte)(void);			/* Special calling convention */
X 	void (*get_byte)(void);			/* Special calling convention */
@@ -50,50 +50,13 @@
X 
X #define EXTRA_THREAD_STRUCT							\
X 	uaccess_t	*uaccess;		/* User access functions*/	\
-	struct context_save_struct *save;					\
-	unsigned long	memmap;							\
X 	unsigned long	memcmap[256];
X 
X #define EXTRA_THREAD_STRUCT_INIT		\
-	&uaccess_kernel,			\
-	0,					\
-	(unsigned long) swapper_pg_dir,		\
+	,&uaccess_kernel,			\
X 	{ 0, }
X 
-DECLARE_THREAD_STRUCT;
-
-/*
- * Return saved PC of a blocked thread.
- */
-extern __inline__ unsigned long thread_saved_pc (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->pc & ~PCMASK;
-	else
-		return 0;
-}
-
-extern __inline__ unsigned long get_css_fp (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->fp;
-	else
-		return 0;
-}
-
-asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
-
-extern __inline__ void copy_thread_css (struct context_save_struct *save)
-{
-	save->r4 =
-	save->r5 =
-	save->r6 =
-	save->r7 =
-	save->r8 =
-	save->r9 =
-	save->fp = 0;
-	save->pc = ((unsigned long)ret_from_sys_call) | SVC26_MODE;
-}
+#define SWAPPER_PG_DIR ((unsigned long)swapper_pg_dir)
X 
X #define start_thread(regs,pc,sp)					\
X ({									\
@@ -105,18 +68,16 @@
X 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
X 	regs->ARM_r1 = stack[1];	/* r1 (argv) */			\
X 	regs->ARM_r0 = stack[0];	/* r0 (argc) */			\
-	flush_tlb_mm(current->mm);					\
X })
X 
X /* Allocation and freeing of basic task resources. */
X /*
X  * NOTE! The task struct and the stack go together
X  */
-#define alloc_task_struct() \
-	((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p)    free_pages((unsigned long)(p),1)
-
+extern unsigned long get_page_8k(int priority);
+extern void free_page_8k(unsigned long page);
X 
-#endif
+#define ll_alloc_task_struct()	((struct task_struct *)get_page_8k(GFP_KERNEL))
+#define ll_free_task_struct(p)  free_page_8k((unsigned long)(p))
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h
--- v2.2.7/linux/include/asm-arm/proc-armo/ptrace.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-armo/ptrace.h	Sat May  8 11:06:57 1999
@@ -68,8 +68,13 @@
X /* Are the current registers suitable for user mode?
X  * (used to maintain security in signal handlers)
X  */
-#define valid_user_regs(regs) \
-	(user_mode(regs) && ((regs)->ARM_sp & 3) == 0)
+static inline int valid_user_regs(struct pt_regs *regs)
+{
+	if (!user_mode(regs) || regs->ARM_pc & (F_BIT | I_BIT))
+		return 1;
+
+	return 0;
+}
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/semaphore.h linux/include/asm-arm/proc-armo/semaphore.h
--- v2.2.7/linux/include/asm-arm/proc-armo/semaphore.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/semaphore.h	Sat May  8 11:06:57 1999
@@ -13,17 +13,19 @@
X 	__asm__ __volatile__ ("
X 	@ atomic down operation
X 	mov	r0, pc
-	orr	r1, r0, #0x08000000
+	orr	lr, r0, #0x08000000
X 	and	r0, r0, #0x0c000003
-	teqp	r1, #0
-	ldr	r1, [%0]
-	subs	r1, r1, #1
-	str	r1, [%0]
-	mov	r1, pc, lsr #28
-	teqp	r0, r1, lsl #28
+	teqp	lr, #0
+	ldr	lr, [%0]
+	subs	lr, lr, #1
+	str	lr, [%0]
+	mov	lr, pc, lsr #28
+	teqp	r0, lr, lsl #28
X 	movmi	r0, %0
-	blmi	" SYMBOL_NAME_STR(__down)
-		: : "r" (sem) : "r0", "r1", "r2", "r3", "ip", "lr", "cc");
+	blmi	" SYMBOL_NAME_STR(__down_failed)
+		:
+		: "r" (sem)
+		: "r0", "lr", "cc");
X }
X 
X /*
@@ -36,22 +38,47 @@
X 	__asm__ __volatile__ ("
X 	@ atomic down operation
X 	mov	r0, pc
-	orr	r1, r0, #0x08000000
+	orr	lr, r0, #0x08000000
X 	and	r0, r0, #0x0c000003
-	teqp	r1, #0
-	ldr	r1, [%1]
-	subs	r1, r1, #1
-	str	r1, [%1]
-	mov	r1, pc, lsr #28
+	teqp	lr, #0
+	ldr	lr, [%1]
+	subs	lr, lr, #1
+	str	lr, [%1]
+	mov	lr, pc, lsr #28
X 	orrmi	r0, r0, #0x80000000	@ set N
-	teqp	r0, r1, lsl #28
+	teqp	r0, lr, lsl #28
X 	movmi	r0, %1
X 	movpl	r0, #0
-	blmi	" SYMBOL_NAME_STR(__down_interruptible) "
+	blmi	" SYMBOL_NAME_STR(__down_interruptible_failed) "
X 	mov	%0, r0"
X 		: "=r" (result)
X 		: "r" (sem)
-		: "r0", "r1", "r2", "r3", "ip", "lr", "cc");
+		: "r0", "lr", "cc");
+	return result;
+}
+
+extern inline int down_trylock(struct semaphore * sem)
+{
+	int result;
+	__asm__ __volatile__ ("
+	@ atomic down operation
+	mov	r0, pc
+	orr	lr, r0, #0x08000000
+	and	r0, r0, #0x0c000003
+	teqp	lr, #0
+	ldr	lr, [%1]
+	subs	lr, lr, #1
+	str	lr, [%1]
+	mov	lr, pc, lsr #28
+	orrmi	r0, r0, #0x80000000	@ set N
+	teqp	r0, lr, lsl #28
+	movmi	r0, %1
+	movpl	r0, #0
+	blmi	" SYMBOL_NAME_STR(__down_trylock_failed) "
+	mov	%0, r0"
+		: "=r" (result)
+		: "r" (sem)
+		: "r0", "lr", "cc");
X 	return result;
X }
X 
@@ -66,18 +93,20 @@
X 	__asm__ __volatile__ ("
X 	@ atomic up operation
X 	mov	r0, pc
-	orr	r1, r0, #0x08000000
+	orr	lr, r0, #0x08000000
X 	and	r0, r0, #0x0c000003
-	teqp	r1, #0
-	ldr	r1, [%0]
-	adds	r1, r1, #1
-	str	r1, [%0]
-	mov	r1, pc, lsr #28
+	teqp	lr, #0
+	ldr	lr, [%0]
+	adds	lr, lr, #1
+	str	lr, [%0]
+	mov	lr, pc, lsr #28
X 	orrls	r0, r0, #0x80000000	@ set N
-	teqp	r0, r1, lsl #28
+	teqp	r0, lr, lsl #28
X 	movmi	r0, %0
-	blmi	" SYMBOL_NAME_STR(__up)
-		: : "r" (sem) : "r0", "r1", "r2", "r3", "ip", "lr", "cc");
+	blmi	" SYMBOL_NAME_STR(__up_wakeup)
+		:
+		: "r" (sem)
+		: "r0", "lr", "cc");
X }
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/io.h linux/include/asm-arm/proc-armv/io.h
--- v2.2.7/linux/include/asm-arm/proc-armv/io.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/proc-armv/io.h	Sat May  8 11:06:58 1999
@@ -22,17 +22,14 @@
X 
X #include <asm/proc-fns.h>
X 
-extern inline void dma_cache_inv(unsigned long start, unsigned long size)
-{
-	processor.u.armv3v4._cache_purge_area(start, start + size);
-}
+#define dma_cache_inv(start, size)					    \
+	do { processor.u.armv3v4._cache_purge_area((unsigned long)(start),  \
+		((unsigned long)(start)+(size))); } while (0)
X 
-extern inline void dma_cache_wback(unsigned long start, unsigned long size)
-{
-	processor.u.armv3v4._cache_wback_area(start, start + size);
-}
+#define dma_cache_wback(start, size)					    \
+	do { processor.u.armv3v4._cache_wback_area((unsigned long)(start),  \
+		((unsigned long)(start)+(size))); } while (0)
X 
-extern inline void dma_cache_wback_inv(unsigned long start, unsigned long size)
-{
-	processor.u.armv3v4._flush_cache_area(start, start + size, 0);
-}
+#define dma_cache_wback_inv(start, size)				    \
+	do { processor.u.armv3v4._flush_cache_area((unsigned long)(start),  \
+		((unsigned long)(start)+(size)), 0); } while (0)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/mm-init.h linux/include/asm-arm/proc-armv/mm-init.h
--- v2.2.7/linux/include/asm-arm/proc-armv/mm-init.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/proc-armv/mm-init.h	Sat May  8 11:06:58 1999
@@ -37,7 +37,7 @@
X  */
X #include <asm/pgtable.h>
X  
-#define PTE_SIZE (PTRS_PER_PTE * 4)
+#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR)
X 
X extern unsigned long setup_io_pagetables(unsigned long start_mem);
X 
@@ -79,7 +79,7 @@
X alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
X {
X 	pgd_t *pgdp;
-	pmd_t *pmdp, pmd;
+	pmd_t *pmdp;
X 	pte_t *ptep;
X 
X 	pgdp = pgd_offset_k(virt);
@@ -92,46 +92,41 @@
X 
X 		ptep = (pte_t *)memory;
X 		memzero(ptep, PTE_SIZE);
+		memory += PTE_SIZE;
X 
-		pmd_val(pmd) = __virt_to_phys(memory) | PMD_TYPE_TABLE | PMD_DOMAIN(domain);
-		set_pmd(pmdp, pmd);
+		ptep = (pte_t *)memory;
+		memzero(ptep, PTE_SIZE);
+
+		set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
X 
X 		*mem = memory + PTE_SIZE;
X 	}
X 
X 	ptep = pte_offset(pmdp, virt);
X 
-	pte_val(*ptep) = phys | prot | PTE_TYPE_SMALL;
+	set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
X }
X 
X static inline unsigned long
X setup_pagetables(unsigned long start_mem, unsigned long end_mem)
X {
-	unsigned long address;
+	unsigned long address = 0;
X 
-	/*
-	 * map in zero page
-	 */
-	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET), DOMAIN_USER, PTE_CACHEABLE);
-
-	/*
-	 * ensure no mappings in user space
-	 */
-	for (address = PGDIR_SIZE; address < PAGE_OFFSET; address += PGDIR_SIZE)
-		free_init_section(address);
-
-	/*
-	 * map in physical ram & kernel
-	 */
-	for (address = PAGE_OFFSET; address < end_mem; address += PGDIR_SIZE)
-		alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
-				   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
+	do {
+		if (address >= PAGE_OFFSET && address < end_mem)
+			/*
+			 * map in physical ram & kernel
+			 */
+			alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
+					   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
+		else
+			/*
+			 * unmap everything else
+			 */
+			free_init_section(address);
X 
-	/*
-	 * unmap everything else
-	 */
-	for (address = end_mem; address; address += PGDIR_SIZE)
-		free_init_section(address);
+		address += PGDIR_SIZE;
+	} while (address != 0);
X 
X 	/*
X 	 * An area to invalidate the cache
@@ -144,6 +139,12 @@
X 	 */
X 	start_mem = setup_io_pagetables(start_mem);
X 
+	/*
+	 * map in zero page
+	 */
+	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET),
+			DOMAIN_USER, L_PTE_CACHEABLE | L_PTE_YOUNG | L_PTE_PRESENT);
+
X 	flush_cache_all();
X 
X 	return start_mem;
@@ -156,9 +157,21 @@
X 
X 	*start_mem = smem = PAGE_ALIGN(*start_mem);
X 
+	/*
+	 * Mark all of memory from the end of kernel to end of memory
+	 */
X 	while (smem < end_mem) {
-	    	clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-    		smem += PAGE_SIZE;
+		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
+		smem += PAGE_SIZE;
+	}
+
+	/*
+	 * Mark memory from page 1 to start of the swapper page directory
+	 */
+	smem = PAGE_OFFSET + PAGE_SIZE;
+	while (smem < (unsigned long)&swapper_pg_dir) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
+		smem += PAGE_SIZE;
X 	}
X }	
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.2.7/linux/include/asm-arm/proc-armv/pgtable.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-armv/pgtable.h	Sat May  8 11:06:58 1999
@@ -3,14 +3,15 @@
X  *
X  * Copyright (C) 1995, 1996, 1997 Russell King
X  *
- * 12-01-1997	RMK	Altered flushing routines to use function pointers
+ * 12-Jan-1997	RMK	Altered flushing routines to use function pointers
X  *			now possible to combine ARM6, ARM7 and StrongARM versions.
+ * 17-Apr-1999	RMK	Now pass an area size to clean_cache_area and
+ *			flush_icache_area.
X  */
X #ifndef __ASM_PROC_PGTABLE_H
X #define __ASM_PROC_PGTABLE_H
X 
-#include <asm/arch/mmu.h>
-#include <asm/arch/processor.h>		/* For TASK_SIZE */
+#include <asm/arch/memory.h>		/* For TASK_SIZE */
X 
X #define LIBRARY_TEXT_START 0x0c000000
X 
@@ -41,8 +42,23 @@
X 				 ((_vma)->vm_flags & VM_EXEC) ? 1 : 0);	\
X 	} while (0)
X 
+#define clean_cache_range(_start,_end)					\
+	do {								\
+		unsigned long _s, _sz;					\
+		_s = (unsigned long)_start;				\
+		_sz = (unsigned long)_end - _s;				\
+		processor.u.armv3v4._clean_cache_area(_s, _sz);		\
+	} while (0)
+
+#define clean_cache_area(_start,_size)					\
+	do {								\
+		unsigned long _s;					\
+		_s = (unsigned long)_start;				\
+		processor.u.armv3v4._clean_cache_area(_s, _size);	\
+	} while (0)
+
X #define flush_icache_range(_start,_end)					\
-	processor.u.armv3v4._flush_icache_area((_start), (_end))
+	processor.u.armv3v4._flush_icache_area((_start), (_end) - (_start))
X 
X /*
X  * We don't have a MEMC chip...
@@ -60,12 +76,6 @@
X 	processor.u.armv3v4._flush_ram_page ((_page) & PAGE_MASK);
X 
X /*
- * Make the page uncacheable (must flush page beforehand).
- */
-#define uncache_page(_page)						\
-	processor.u.armv3v4._flush_ram_page ((_page) & PAGE_MASK);
-
-/*
X  * TLB flushing:
X  *
X  *  - flush_tlb() flushes the current mm struct TLBs
@@ -106,22 +116,15 @@
X 	} while (0)
X 
X /*
- * Since the page tables are in cached memory, we need to flush the dirty
- * data cached entries back before we flush the tlb...  This is also useful
- * to flush out the SWI instruction for signal handlers...
+ * PMD_SHIFT determines the size of the area a second-level page table can map
X  */
-#define __flush_entry_to_ram(entry)						\
-	processor.u.armv3v4._flush_cache_entry((unsigned long)(entry))
-
-#define __flush_pte_to_ram(entry)						\
-	processor.u.armv3v4._flush_cache_pte((unsigned long)(entry))
-
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
X #define PMD_SHIFT       20
X #define PMD_SIZE        (1UL << PMD_SHIFT)
X #define PMD_MASK        (~(PMD_SIZE-1))
X 
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
+/*
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
X #define PGDIR_SHIFT     20
X #define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
X #define PGDIR_MASK      (~(PGDIR_SIZE-1))
@@ -135,6 +138,7 @@
X #define PTRS_PER_PGD    4096
X #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
X 
+
X /* Just any arbitrary offset to the start of the vmalloc VM area: the
X  * current 8MB value just means that there will be a 8MB "hole" after the
X  * physical memory until the kernel virtual memory starts.  That means that
@@ -147,87 +151,28 @@
X #define VMALLOC_VMADDR(x) ((unsigned long)(x))
X #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
X 
-/* PMD types (actually level 1 descriptor) */
-#define PMD_TYPE_MASK		0x0003
-#define PMD_TYPE_FAULT		0x0000
-#define PMD_TYPE_TABLE		0x0001
-#define PMD_TYPE_SECT		0x0002
-#define PMD_UPDATABLE		0x0010
-#define PMD_SECT_CACHEABLE	0x0008
-#define PMD_SECT_BUFFERABLE	0x0004
-#define PMD_SECT_AP_WRITE	0x0400
-#define PMD_SECT_AP_READ	0x0800
-#define PMD_DOMAIN(x)		((x) << 5)
-
-/* PTE types (actially level 2 descriptor) */
-#define PTE_TYPE_MASK	0x0003
-#define PTE_TYPE_FAULT	0x0000
-#define PTE_TYPE_LARGE	0x0001
-#define PTE_TYPE_SMALL	0x0002
-#define PTE_AP_READ	0x0aa0
-#define PTE_AP_WRITE	0x0550
-#define PTE_CACHEABLE	0x0008
-#define PTE_BUFFERABLE	0x0004
X 
-/* Domains */
+/*
+ * Domains
+ */
X #define DOMAIN_USER	0
X #define DOMAIN_KERNEL	1
X #define DOMAIN_TABLE	1
X #define DOMAIN_IO	2
X 
-#define _PAGE_CHG_MASK  (0xfffff00c | PTE_TYPE_MASK)
X 
-/*
- * We define the bits in the page tables as follows:
- *  PTE_BUFFERABLE	page is dirty
- *  PTE_AP_WRITE	page is writable
- *  PTE_AP_READ		page is a young (unsetting this causes faults for any access)
- *  PTE_CACHEABLE       page is readable
- *
- * A page will not be made writable without the dirty bit set.
- * It is not legal to have a writable non-dirty page though (it breaks).
- *
- * A readable page is marked as being cacheable.
- * Youngness is indicated by hardware read.  If the page is old,
- * then we will fault and make the page young again.
- */
-#define _PTE_YOUNG	PTE_AP_READ
-#define _PTE_DIRTY	PTE_BUFFERABLE
-#define _PTE_READ	PTE_CACHEABLE
-#define _PTE_WRITE	PTE_AP_WRITE
-
-#define PAGE_NONE       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG)
-#define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ | _PTE_WRITE)
-#define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
-#define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
-#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | _PTE_READ  | _PTE_DIRTY | _PTE_WRITE)
X 
-#define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
-#define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
+#undef TEST_VERIFY_AREA
X 
X /*
- * The arm can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The sa110 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
X  */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
-#define __P010  PAGE_COPY
-#define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
-#define __P110  PAGE_COPY
-#define __P111  PAGE_COPY
-
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
-#define __S010  PAGE_SHARED
-#define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
-#define __S110  PAGE_SHARED
-#define __S111  PAGE_SHARED
+extern __inline__ void update_mmu_cache(struct vm_area_struct * vma,
+	unsigned long address, pte_t pte)
+{
+}
X 
-#undef TEST_VERIFY_AREA
X 
X /*
X  * BAD_PAGETABLE is used when we need a bogus page-table, while
@@ -240,97 +185,40 @@
X extern pte_t * __bad_pagetable(void);
X extern unsigned long *empty_zero_page;
X 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define BAD_PAGETABLE	__bad_pagetable()
+#define BAD_PAGE	__bad_page()
+#define ZERO_PAGE	((unsigned long) empty_zero_page)
X 
X /* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR			(sizeof(unsigned long))
-#define BITS_PER_PTR                    (8*BYTES_PER_PTR)
+#define BYTES_PER_PTR	(sizeof(unsigned long))
+#define BITS_PER_PTR	(8*BYTES_PER_PTR)
X 
X /* to align the pointer to a pointer address */
-#define PTR_MASK                        (~(sizeof(void*)-1))
+#define PTR_MASK	(~(sizeof(void*)-1))
X 
X /* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2                 2
+#define SIZEOF_PTR_LOG2	2
X 
X /* to find an entry in a page-table */
X #define PAGE_PTR(address) \
X ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
X 
-/* to set the page-dir */
+/* to set the page-dir
+ * Note that we need to flush the cache and TLBs
+ * if we are affecting the current task.
+ */
X #define SET_PAGE_DIR(tsk,pgdir)					\
X do {								\
X 	tsk->tss.memmap = __virt_to_phys((unsigned long)pgdir);	\
-	if ((tsk) == current)					\
+	if ((tsk) == current) {					\
+		flush_cache_all();				\
X 		__asm__ __volatile__(				\
X 		"mcr%?	p15, 0, %0, c2, c0, 0\n"		\
X 		: : "r" (tsk->tss.memmap));			\
+		flush_tlb_all();				\
+	}							\
X } while (0)
X 
-extern __inline__ int pte_none(pte_t pte)
-{
-	return !pte_val(pte);
-}
-
-#define pte_clear(ptep)	set_pte(ptep, __pte(0))
-
-extern __inline__ int pte_present(pte_t pte)
-{
-#if 0
-	/* This is what it really does, the else
-	   part is just to make it easier for the compiler */
-	switch (pte_val(pte) & PTE_TYPE_MASK) {
-	case PTE_TYPE_LARGE:
-	case PTE_TYPE_SMALL:
-		return 1;
-	default:
-		return 0;
-	}
-#else
-	return ((pte_val(pte) + 1) & 2);
-#endif
-}
-
-extern __inline__ int pmd_none(pmd_t pmd)
-{
-	return !pmd_val(pmd);
-}
-
-#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0))
-
-extern __inline__ int pmd_bad(pmd_t pmd)
-{
-#if 0
-	/* This is what it really does, the else
-	   part is just to make it easier for the compiler */
-	switch (pmd_val(pmd) & PMD_TYPE_MASK) {
-	case PMD_TYPE_FAULT:
-	case PMD_TYPE_TABLE:
-		return 0;
-	default:
-		return 1;
-	}
-#else
-	return pmd_val(pmd) & 2;
-#endif
-}
-
-extern __inline__ int pmd_present(pmd_t pmd)
-{
-#if 0
-	/* This is what it really does, the else
-	   part is just to make it easier for the compiler */
-	switch (pmd_val(pmd) & PMD_TYPE_MASK) {
-	case PMD_TYPE_TABLE:
-		return 1;
-	default:
-		return 0;
-	}
-#else
-	return ((pmd_val(pmd) + 1) & 2);
-#endif
-}
X 
X /*
X  * The "pgd_xxx()" functions here are trivial for a folded two-level
@@ -342,231 +230,224 @@
X #define pgd_present(pgd)	(1)
X #define pgd_clear(pgdp)
X 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-#define pte_read(pte)		(1)
-#define pte_exec(pte)		(1)
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 28'
echo 'File patch-2.2.8 is continued in part 29'
echo 29 > _shar_seq_.tmp
#!/bin/sh
# this is part 29 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 29; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 
-extern __inline__ int pte_write(pte_t pte)
+/* to find an entry in a page-table-directory */
+extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
X {
-	return pte_val(pte) & _PTE_WRITE;
+	return mm->pgd + (address >> PGDIR_SHIFT);
X }
X 
-extern __inline__ int pte_dirty(pte_t pte)
-{
-	return pte_val(pte) & _PTE_DIRTY;
-}
+extern unsigned long get_page_2k(int priority);
+extern void free_page_2k(unsigned long page);
X 
-extern __inline__ int pte_young(pte_t pte)
-{
-	return pte_val(pte) & _PTE_YOUNG;
-}
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
X 
-extern __inline__ pte_t pte_wrprotect(pte_t pte)
-{
-	pte_val(pte) &= ~_PTE_WRITE;
-	return pte;
-}
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
X 
-extern __inline__ pte_t pte_nocache(pte_t pte)
-{
-	pte_val(pte) &= ~PTE_CACHEABLE;
-	return pte;
-}
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#else
+#error Pgtable caches have to be per-CPU, so that no locking is needed.
+#endif
X 
-extern __inline__ pte_t pte_mkclean(pte_t pte)
-{
-	pte_val(pte) &= ~_PTE_DIRTY;
-	return pte;
-}
+extern pgd_t *get_pgd_slow(void);
X 
-extern __inline__ pte_t pte_mkold(pte_t pte)
+extern __inline__ pgd_t *get_pgd_fast(void)
X {
-	pte_val(pte) &= ~_PTE_YOUNG;
-	return pte;
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		clean_cache_area(ret, 4);
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
X }
X 
-extern __inline__ pte_t pte_mkwrite(pte_t pte)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
X {
-	pte_val(pte) |= _PTE_WRITE;
-	return pte;
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
X }
X 
-extern __inline__ pte_t pte_mkdirty(pte_t pte)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
X {
-	pte_val(pte) |= _PTE_DIRTY;
-	return pte;
+	free_pages((unsigned long) pgd, 2);
X }
X 
-extern __inline__ pte_t pte_mkyoung(pte_t pte)
+#define pgd_free(pgd)		free_pgd_fast(pgd)
+#define pgd_alloc()		get_pgd_fast()
+
+extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
X {
-	pte_val(pte) |= _PTE_YOUNG;
-	return pte;
+	struct task_struct * p;
+	pgd_t *pgd;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
X }
X 
-/*
- * The following are unable to be implemented on this MMU
- */
-#if 0
-extern __inline__ pte_t pte_rdprotect(pte_t pte)
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/****************
+* PMD functions *
+****************/
+
+/* PMD types (actually level 1 descriptor) */
+#define PMD_TYPE_MASK		0x0003
+#define PMD_TYPE_FAULT		0x0000
+#define PMD_TYPE_TABLE		0x0001
+#define PMD_TYPE_SECT		0x0002
+#define PMD_UPDATABLE		0x0010
+#define PMD_SECT_CACHEABLE	0x0008
+#define PMD_SECT_BUFFERABLE	0x0004
+#define PMD_SECT_AP_WRITE	0x0400
+#define PMD_SECT_AP_READ	0x0800
+#define PMD_DOMAIN(x)		((x) << 5)
+
+#define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
+#define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
+
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define pmd_clear(pmdp)		set_pmd(pmdp, __pmd(0))
+#define pmd_bad(pmd)		(pmd_val(pmd) & 2)
+#define mk_user_pmd(ptep)	__mk_pmd(ptep, _PAGE_USER_TABLE)
+#define mk_kernel_pmd(ptep)	__mk_pmd(ptep, _PAGE_KERNEL_TABLE)
+#define set_pmd(pmdp,pmd)	processor.u.armv3v4._set_pmd(pmdp,pmd)
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, address) ((pmd_t *)(dir))
+
+extern __inline__ int pmd_present(pmd_t pmd)
X {
-	pte_val(pte) &= ~(PTE_CACHEABLE|PTE_AP_READ);
-	return pte;
+	return ((pmd_val(pmd) + 1) & 2);
X }
X 
-extern __inline__ pte_t pte_exprotect(pte_t pte)
+/* We don't use pmd cache, so this is a dummy routine */
+extern __inline__ pmd_t *get_pmd_fast(void)
X {
-	pte_val(pte) &= ~(PTE_CACHEABLE|PTE_AP_READ);
-	return pte;
+	return (pmd_t *)0;
X }
X 
-extern __inline__ pte_t pte_mkread(pte_t pte)
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
X {
-	pte_val(pte) |= PTE_CACHEABLE;
-	return pte;
X }
X 
-extern __inline__ pte_t pte_mkexec(pte_t pte)
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
X {
-	pte_val(pte) |= PTE_CACHEABLE;
-	return pte;
X }
-#endif
+
+extern void __bad_pmd(pmd_t *pmd);
+extern void __bad_pmd_kernel(pmd_t *pmd);
X 
X /*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
X  */
-extern __inline__ pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+extern __inline__ void pmd_free(pmd_t *pmd)
X {
-	pte_t pte;
-	pte_val(pte) = __virt_to_phys(page) | pgprot_val(pgprot);
-	return pte;
X }
X 
-/* This takes a physical page address that is used by the remapping functions */
-extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
X {
-	pte_t pte;
-	pte_val(pte) = physpage + pgprot_val(pgprot);
-	return pte;
+	return (pmd_t *) pgd;
X }
X 
-extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
-	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
-	return pte;
-}
+#define pmd_free_kernel		pmd_free
+#define pmd_alloc_kernel	pmd_alloc
X 
-extern __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
+extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
X {
-	*pteptr = pteval;
-	__flush_pte_to_ram(pteptr);
-}
+	unsigned long pte_ptr = (unsigned long)ptep;
+	pmd_t pmd;
X 
-extern __inline__ unsigned long pte_page(pte_t pte)
-{
-	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
-}
+	pte_ptr -= PTRS_PER_PTE * BYTES_PER_PTR;
X 
-extern __inline__ pmd_t mk_user_pmd(pte_t *ptep)
-{
-	pmd_t pmd;
-	pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_USER_TABLE;
-	return pmd;
-}
+	/*
+	 * The pmd must be loaded with the physical
+	 * address of the PTE table
+	 */
+	pmd_val(pmd) = __virt_to_phys(pte_ptr) | prot;
X 
-extern __inline__ pmd_t mk_kernel_pmd(pte_t *ptep)
-{
-	pmd_t pmd;
-	pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_KERNEL_TABLE;
X 	return pmd;
X }
X 
-#if 1
-#define set_pmd(pmdp,pmd) processor.u.armv3v4._set_pmd(pmdp,pmd)
-#else
-extern __inline__ void set_pmd(pmd_t *pmdp, pmd_t pmd)
-{
-	*pmdp = pmd;
-	__flush_pte_to_ram(pmdp);
-}
-#endif
-
X extern __inline__ unsigned long pmd_page(pmd_t pmd)
X {
-	return __phys_to_virt(pmd_val(pmd) & 0xfffffc00);
-}
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+	unsigned long ptr;
X 
-/* to find an entry in a page-table-directory */
-extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-	return mm->pgd + (address >> PGDIR_SHIFT);
-}
+	ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * BYTES_PER_PTR - 1);
X 
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, address) ((pmd_t *)(dir))
+	ptr += PTRS_PER_PTE * BYTES_PER_PTR;
X 
-/* Find an entry in the third-level page table.. */
-extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
-	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+	return __phys_to_virt(ptr);
X }
X 
-extern unsigned long get_small_page(int priority);
-extern void free_small_page(unsigned long page);
X 
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
-#ifndef __SMP__
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
+/****************
+* PTE functions *
+****************/
X 
-#define pgd_quicklist (quicklists.pgd_cache)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (quicklists.pte_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-#else
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif
+/* PTE types (actially level 2 descriptor) */
+#define PTE_TYPE_MASK		0x0003
+#define PTE_TYPE_FAULT		0x0000
+#define PTE_TYPE_LARGE		0x0001
+#define PTE_TYPE_SMALL		0x0002
+#define PTE_AP_READ		0x0aa0
+#define PTE_AP_WRITE		0x0550
+#define PTE_CACHEABLE		0x0008
+#define PTE_BUFFERABLE		0x0004
X 
-extern pgd_t *get_pgd_slow(void);
+#define pte_none(pte)		(!pte_val(pte))
+#define pte_clear(ptep)		set_pte(ptep, __pte(0))
X 
-extern __inline__ pgd_t *get_pgd_fast(void)
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern __inline__ pte_t mk_pte(unsigned long page, pgprot_t pgprot)
X {
-	unsigned long *ret;
-
-	if((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size--;
-	} else
-		ret = (unsigned long *)get_pgd_slow();
-	return (pgd_t *)ret;
+	pte_t pte;
+	pte_val(pte) = __virt_to_phys(page) | pgprot_val(pgprot);
+	return pte;
X }
X 
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+/* This takes a physical page address that is used by the remapping functions */
+extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
X {
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
+	pte_t pte;
+	pte_val(pte) = physpage + pgprot_val(pgprot);
+	return pte;
X }
X 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+#define set_pte(ptep, pte)	processor.u.armv3v4._set_pte(ptep,pte)
+
+extern __inline__ unsigned long pte_page(pte_t pte)
X {
-	free_pages((unsigned long) pgd, 2);
+	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
X }
X 
X extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
@@ -579,6 +460,7 @@
X 	if((ret = (unsigned long *)pte_quicklist) != NULL) {
X 		pte_quicklist = (unsigned long *)(*ret);
X 		ret[0] = ret[1];
+		clean_cache_area(ret, 4);
X 		pgtable_cache_size--;
X 	}
X 	return (pte_t *)ret;
@@ -593,31 +475,124 @@
X 
X extern __inline__ void free_pte_slow(pte_t *pte)
X {
-	free_small_page((unsigned long)pte);
+	free_page_2k((unsigned long)(pte - PTRS_PER_PTE));
X }
X 
-/* We don't use pmd cache, so this is a dummy routine */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
+#define pte_free_kernel(pte)	free_pte_fast(pte)
+#define pte_free(pte)		free_pte_fast(pte)
X 
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
+/*###############################################################################
+ * New PageTableEntry stuff...
+ */
+/* We now keep two sets of ptes - the physical and the linux version.
+ * This gives us many advantages, and allows us greater flexibility.
+ *
+ * The Linux pte's contain:
+ *  bit   meaning
+ *   0    page present
+ *   1    young
+ *   2    bufferable	- matches physical pte
+ *   3    cacheable	- matches physical pte
+ *   4    user
+ *   5    write
+ *   6    execute
+ *   7    dirty
+ *  8-11  unused
+ *  12-31 virtual page address
+ *
+ * These are stored at the pte pointer; the physical PTE is at -1024bytes
+ */
+#define L_PTE_PRESENT		(1 << 0)
+#define L_PTE_YOUNG		(1 << 1)
+#define L_PTE_BUFFERABLE	(1 << 2)
+#define L_PTE_CACHEABLE		(1 << 3)
+#define L_PTE_USER		(1 << 4)
+#define L_PTE_WRITE		(1 << 5)
+#define L_PTE_EXEC		(1 << 6)
+#define L_PTE_DIRTY		(1 << 7)
+
+/*
+ * The following macros handle the cache and bufferable bits...
+ */
+#define _L_PTE_DEFAULT	L_PTE_PRESENT | L_PTE_YOUNG
+#define _L_PTE_READ	L_PTE_USER | L_PTE_CACHEABLE
+#define _L_PTE_EXEC	_L_PTE_READ | L_PTE_EXEC
+
+#define PAGE_NONE       __pgprot(_L_PTE_DEFAULT)
+#define PAGE_COPY       __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE)
+#define PAGE_SHARED     __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE | L_PTE_WRITE)
+#define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_KERNEL     __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
+
+#define _PAGE_CHG_MASK		(PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
+
+/*
+ * The table below defines the page protection levels that we insert into our
+ * Linux page table version.  These get translated into the best that the
+ * architecture can perform.  Note that on most ARM hardware:
+ *  1) We cannot do execute protection
+ *  2) If we could do execute protection, then read is implied
+ *  3) write implies read permissions
+ */
+#define __P000  PAGE_NONE
+#define __P001  PAGE_READONLY
+#define __P010  PAGE_COPY
+#define __P011  PAGE_COPY
+#define __P100  PAGE_READONLY
+#define __P101  PAGE_READONLY
+#define __P110  PAGE_COPY
+#define __P111  PAGE_COPY
+
+#define __S000  PAGE_NONE
+#define __S001  PAGE_READONLY
+#define __S010  PAGE_SHARED
+#define __S011  PAGE_SHARED
+#define __S100  PAGE_READONLY
+#define __S101  PAGE_READONLY
+#define __S110  PAGE_SHARED
+#define __S111  PAGE_SHARED
+
+
+
+#define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+#define pte_read(pte)			(pte_val(pte) & L_PTE_USER)
+#define pte_write(pte)			(pte_val(pte) & L_PTE_WRITE)
+#define pte_exec(pte)			(pte_val(pte) & L_PTE_EXEC)
+#define pte_dirty(pte)			(pte_val(pte) & L_PTE_DIRTY)
+#define pte_young(pte)			(pte_val(pte) & L_PTE_YOUNG)
+
+#define PTE_BIT_FUNC(fn,op)			\
+extern inline pte_t fn##(pte_t pte) { pte_val(pte) op##; return pte; }
+
+//PTE_BIT_FUNC(pte_rdprotect, &= ~L_PTE_USER);
+PTE_BIT_FUNC(pte_wrprotect, &= ~L_PTE_WRITE);
+PTE_BIT_FUNC(pte_exprotect, &= ~L_PTE_EXEC);
+PTE_BIT_FUNC(pte_mkclean,   &= ~L_PTE_DIRTY);
+PTE_BIT_FUNC(pte_mkold,     &= ~L_PTE_YOUNG);
+//PTE_BIT_FUNC(pte_mkread,    |= L_PTE_USER);
+PTE_BIT_FUNC(pte_mkwrite,   |= L_PTE_WRITE);
+PTE_BIT_FUNC(pte_mkexec,    |= L_PTE_EXEC);
+PTE_BIT_FUNC(pte_mkdirty,   |= L_PTE_DIRTY);
+PTE_BIT_FUNC(pte_mkyoung,   |= L_PTE_YOUNG);
+PTE_BIT_FUNC(pte_nocache,   &= ~L_PTE_CACHEABLE);
+
+extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
X {
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	return pte;
X }
X 
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
+/* Find an entry in the third-level page table.. */
+extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address)
X {
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
X }
X 
-extern void __bad_pmd(pmd_t *pmd);
-extern void __bad_pmd_kernel(pmd_t *pmd);
-
-#define pte_free_kernel(pte)	free_pte_fast(pte)
-#define pte_free(pte)		free_pte_fast(pte)
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
-
X extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
X {
X 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -653,49 +628,6 @@
X 		return NULL;
X 	}
X 	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern __inline__ void pmd_free(pmd_t *pmd)
-{
-}
-
-extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	return (pmd_t *) pgd;
-}
-
-#define pmd_free_kernel		pmd_free
-#define pmd_alloc_kernel	pmd_alloc
-
-extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
-{
-	struct task_struct * p;
-	pgd_t *pgd;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
-		pgd[address >> PGDIR_SHIFT] = entry;
-}
-
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-/*
- * The sa110 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- */
-extern __inline__ void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t pte)
-{
X }
X 
X #define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h
--- v2.2.7/linux/include/asm-arm/proc-armv/processor.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/proc-armv/processor.h	Sat May  8 11:06:58 1999
@@ -12,8 +12,6 @@
X #ifndef __ASM_PROC_PROCESSOR_H
X #define __ASM_PROC_PROCESSOR_H
X 
-#ifdef __KERNEL__
- 
X #define KERNEL_STACK_SIZE	PAGE_SIZE
X 
X struct context_save_struct {
@@ -28,56 +26,18 @@
X 	unsigned long pc;
X };
X 
-#define EXTRA_THREAD_STRUCT \
-	struct context_save_struct *save;		\
-	unsigned long memmap;
+#define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0 }
X 
-#define EXTRA_THREAD_STRUCT_INIT			\
-	0,						\
-	((unsigned long) swapper_pg_dir) - PAGE_OFFSET
-
-DECLARE_THREAD_STRUCT;
-
-/*
- * Return saved PC of a blocked thread.
- */
-extern __inline__ unsigned long thread_saved_pc (struct thread_struct *t)
-{
-	if (t->save)
- return t->save->pc;
-	else
-		return 0;
-}
-
-extern __inline__ unsigned long get_css_fp (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->fp;
-	else
-		return 0;
-}
-
-asmlinkage void ret_from_sys_call(void) __asm__ ("ret_from_sys_call");
-
-extern __inline__ void copy_thread_css (struct context_save_struct *save)
-{
- save->cpsr = SVC_MODE;
-	save->r4 =
-	save->r5 =
-	save->r6 =
-	save->r7 =
-	save->r8 =
-	save->r9 =
-	save->fp = 0;
-	save->pc = (unsigned long) ret_from_sys_call;
-}
+#define EXTRA_THREAD_STRUCT
+#define EXTRA_THREAD_STRUCT_INIT
+#define SWAPPER_PG_DIR	(((unsigned long)swapper_pg_dir) - PAGE_OFFSET)
X 
X #define start_thread(regs,pc,sp)					\
X ({									\
X 	unsigned long *stack = (unsigned long *)sp;			\
X 	set_fs(USER_DS);						\
X 	memzero(regs->uregs, sizeof(regs->uregs));			\
-	if (current->personality == PER_LINUX_32BIT)			\
+	if (current->personality & ADDR_LIMIT_32BIT)			\
X 		regs->ARM_cpsr = USR_MODE;				\
X 	else								\
X 		regs->ARM_cpsr = USR26_MODE;				\
@@ -92,10 +52,7 @@
X /*
X  * NOTE! The task struct and the stack go together
X  */
-#define alloc_task_struct() \
-	((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p)	free_pages((unsigned long)(p),1)
-
-#endif
+#define ll_alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define ll_free_task_struct(p) free_pages((unsigned long)(p),1)
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/ptrace.h linux/include/asm-arm/proc-armv/ptrace.h
--- v2.2.7/linux/include/asm-arm/proc-armv/ptrace.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-armv/ptrace.h	Sat May  8 11:06:58 1999
@@ -52,9 +52,14 @@
X #define CC_Z_BIT	(1 << 30)
X #define CC_N_BIT	(1 << 31)
X 
+#if 0 /* GCC/egcs should be able to optimise this, IMHO */
X #define user_mode(regs)	\
X 	((((regs)->ARM_cpsr & MODE_MASK) == USR_MODE) || \
X 	 (((regs)->ARM_cpsr & MODE_MASK) == USR26_MODE))
+#else
+#define user_mode(regs)	\
+	(((regs)->ARM_cpsr & 0xf) == 0)
+#endif
X 
X #define processor_mode(regs) \
X 	((regs)->ARM_cpsr & MODE_MASK)
@@ -74,8 +79,19 @@
X /* Are the current registers suitable for user mode?
X  * (used to maintain security in signal handlers)
X  */
-#define valid_user_regs(regs) \
-	(user_mode(regs) && ((regs)->ARM_sp & 3) == 0)
+static inline int valid_user_regs(struct pt_regs *regs)
+{
+	if ((regs->ARM_cpsr & 0xf) == 0 ||
+	    (regs->ARM_cpsr & (F_BIT|I_BIT)))
+		return 1;
+
+	/*
+	 * Force CPSR to something logical...
+	 */
+	regs->ARM_cpsr &= (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT|0x10);
+
+	return 0;
+}
X 
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/semaphore.h linux/include/asm-arm/proc-armv/semaphore.h
--- v2.2.7/linux/include/asm-arm/proc-armv/semaphore.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/proc-armv/semaphore.h	Sat May  8 11:06:58 1999
@@ -60,6 +60,32 @@
X 	return temp;
X }
X 
+extern inline int down_trylock(struct semaphore *sem)
+{
+	unsigned int cpsr, temp;
+
+	__asm__ __volatile__ ("
+	@ atomic down try lock operation
+	mrs	%0, cpsr
+	orr	%1, %0, #128		@ disable IRQs
+	bic	%0, %0, #0x80000000	@ clear N
+	msr	cpsr, %1
+	ldr	%1, [%2]
+	subs	%1, %1, #1
+	orrmi	%0, %0, #0x80000000	@ set N
+	str	%1, [%2]
+	msr	cpsr, %0
+	movmi	r0, %2
+	movpl	r0, #0
+	blmi	" SYMBOL_NAME_STR(__down_trylock_failed) "
+	mov	%1, r0"
+		: "=&r" (cpsr), "=&r" (temp)
+		: "r" (sem)
+		: "r0", "lr", "cc");
+
+	return temp;
+}
+
X /*
X  * Note! This is subtle. We jump to wake people up only if
X  * the semaphore was negative (== somebody was waiting on it).
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h
--- v2.2.7/linux/include/asm-arm/proc-armv/uaccess.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/proc-armv/uaccess.h	Sat May  8 11:06:58 1999
@@ -133,6 +133,7 @@
X 	"	.section .fixup,\"ax\"\n"			\
X 	"	.align	2\n"					\
X 	"3:	mvn	%0, %3\n"				\
+	"	mov	%1, #0\n"				\
X 	"	b	2b\n"					\
X 	"	.previous\n"					\
X 	"	.section __ex_table,\"a\"\n"			\
@@ -153,6 +154,7 @@
X 	"	.section .fixup,\"ax\"\n"			\
X 	"	.align	2\n"					\
X 	"4:	mvn	%0, %5\n"				\
+	"	mov	%1, #0\n"				\
X 	"	b	3b\n"					\
X 	"	.previous\n"					\
X 	"	.section __ex_table,\"a\"\n"			\
@@ -173,6 +175,7 @@
X 	"	.section .fixup,\"ax\"\n"			\
X 	"	.align	2\n"					\
X 	"3:	mvn	%0, %3\n"				\
+	"	mov	%1, #0\n"				\
X 	"	b	2b\n"					\
X 	"	.previous\n"					\
X 	"	.section __ex_table,\"a\"\n"			\
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.2.7/linux/include/asm-arm/proc-fns.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-fns.h	Sat May  8 11:07:16 1999
@@ -9,6 +9,10 @@
X #include <asm/page.h>
X 
X #ifdef __KERNEL__
+
+/* forward-decare task_struct */
+struct task_struct;
+
X /*
X  * Don't change this structure
X  */
@@ -18,7 +22,7 @@
X 	 *
X 	 * flush caches for task switch
X 	 */
-	void (*_switch_to)(void *prev, void *next);
+	struct task_struct *(*_switch_to)(struct task_struct *prev, struct task_struct *next);
X 	/*
X 	 * get data abort address/flags
X 	 */
@@ -54,10 +58,10 @@
X 			 */
X 			void (*_flush_cache_entry)(unsigned long address);
X 			/*
-			 * flush a virtual address used for a page table
-			 * note D-cache only!
+			 * clean a virtual address range from the
+			 * D-cache without flushing the cache.
X 			 */
-			void (*_flush_cache_pte)(unsigned long address);
+			void (*_clean_cache_area)(unsigned long start, unsigned long size);
X 			/*
X 			 * flush a page to RAM
X 			 */
@@ -76,13 +80,17 @@
X 			 */
X 			void (*_set_pmd)(pmd_t *pmdp, pmd_t pmd);
X 			/*
+			 * Set a PTE
+			 */
+			void (*_set_pte)(pte_t *ptep, pte_t pte);
+			/*
X 			 * Special stuff for a reset
X 			 */
X 			unsigned long (*reset)(void);
X 			/*
X 			 * flush an icached page
X 			 */
-			void (*_flush_icache_area)(unsigned long start, unsigned long end);
+			void (*_flush_icache_area)(unsigned long start, unsigned long size);
X 			/*
X 			 * write back dirty cached data
X 			 */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.2.7/linux/include/asm-arm/processor.h	Tue Jan 19 11:32:53 1999
+++ linux/include/asm-arm/processor.h	Sat May  8 11:06:58 1999
@@ -7,12 +7,14 @@
X #ifndef __ASM_ARM_PROCESSOR_H
X #define __ASM_ARM_PROCESSOR_H
X 
+#define FP_SIZE 35
+
X struct fp_hard_struct {
-	unsigned int save[140/4];		/* as yet undefined */
+	unsigned int save[FP_SIZE];		/* as yet undefined */
X };
X 
X struct fp_soft_struct {
-	unsigned int save[140/4];		/* undefined information */
+	unsigned int save[FP_SIZE];		/* undefined information */
X };
X 
X union fp_state {
@@ -22,28 +24,59 @@
X 
X typedef unsigned long mm_segment_t;		/* domain register	*/
X 
-#define NR_DEBUGS	5
+#ifdef __KERNEL__
X 
-#define DECLARE_THREAD_STRUCT							\
-struct thread_struct {								\
-	unsigned long	address;		/* Address of fault	*/	\
-	unsigned long	trap_no;		/* Trap number		*/	\
-	unsigned long	error_code;		/* Error code of trap	*/	\
-	union fp_state	fpstate;		/* FPE save state	*/	\
-	unsigned long	debug[NR_DEBUGS];	/* Debug/ptrace		*/	\
-	EXTRA_THREAD_STRUCT							\
-}
+#include <asm/assembler.h> 
+
+#define NR_DEBUGS	5
X 
X #include <asm/arch/processor.h>
X #include <asm/proc/processor.h>
X 
-#define INIT_TSS  {			\
-	0,				\
-	0,				\
-	0,				\
-	{ { { 0, }, }, },		\
-	{ 0, },				\
-	EXTRA_THREAD_STRUCT_INIT	\
+struct thread_struct {
+	unsigned long			address;	  /* Address of fault	*/
+	unsigned long			trap_no;	  /* Trap number	*/
+	unsigned long			error_code;	  /* Error code of trap	*/
+	union fp_state			fpstate;	  /* FPE save state	*/
+	unsigned long			debug[NR_DEBUGS]; /* Debug/ptrace	*/
+	struct context_save_struct	*save;		  /* context save	*/
+	unsigned long			memmap;		  /* page tables	*/
+	EXTRA_THREAD_STRUCT
+};
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+
+#define INIT_TSS  {				\
+	0,					\
+	0,					\
+	0,					\
+	{ { { 0, }, }, },			\
+	{ 0, },					\
+	(struct context_save_struct *)0,	\
+	SWAPPER_PG_DIR				\
+	EXTRA_THREAD_STRUCT_INIT		\
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
+{
+	return t->save ? t->save->pc & ~PCMASK : 0;
+}
+
+extern __inline__ unsigned long get_css_fp(struct thread_struct *t)
+{
+	return t->save ? t->save->fp : 0;
+}
+
+asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+
+extern __inline__ void init_thread_css(struct context_save_struct *save)
+{
+	*save = INIT_CSS;
+	save->pc |= (unsigned long)ret_from_sys_call;
X }
X 
X /* Forward declaration, a strange C thing */
@@ -57,7 +90,12 @@
X #define release_segments(mm)		do { } while (0)
X #define forget_segments()		do { } while (0)
X 
+extern struct task_struct *alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *);
+
X #define init_task	(init_task_union.task)
X #define init_stack	(init_task_union.stack)
+
+#endif
X 
X #endif /* __ASM_ARM_PROCESSOR_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/semaphore-helper.h linux/include/asm-arm/semaphore-helper.h
--- v2.2.7/linux/include/asm-arm/semaphore-helper.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/semaphore-helper.h	Sat May  8 11:06:58 1999
@@ -0,0 +1,84 @@
+#ifndef ASMARM_SEMAPHORE_HELPER_H
+#define ASMARM_SEMAPHORE_HELPER_H
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (atomic_read(&sem->count) <= 0)
+		sem->waking++;
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking non zero interruptible
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;	
+}
+
+/*
+ * waking_non_zero_try_lock:
+ *	1	failed to lock
+ *	0	got the lock
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking <= 0)
+		atomic_inc(&sem->count);
+	else {
+		sem->waking--;
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.2.7/linux/include/asm-arm/semaphore.h	Tue Jan 19 11:32:53 1999
+++ linux/include/asm-arm/semaphore.h	Sat May  8 11:06:58 1999
@@ -19,49 +19,15 @@
X 
X asmlinkage void __down_failed (void /* special register calling convention */);
X asmlinkage int  __down_interruptible_failed (void /* special register calling convention */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
X asmlinkage void __up_wakeup (void /* special register calling convention */);
X 
X extern void __down(struct semaphore * sem);
X extern int  __down_interruptible(struct semaphore * sem);
+extern int  __down_trylock(struct semaphore * sem);
X extern void __up(struct semaphore * sem);
X 
X #define sema_init(sem, val)	atomic_set(&((sem)->count), (val))
-
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * but on the x86 we need an external synchronizer.
- * Currently this is just the global interrupt lock,
- * bah. Go for a smaller spinlock some day.
- *
- * (On the other hand this shouldn't be in any critical
- * path, so..)
- */
-static inline void wake_one_more(struct semaphore * sem)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	sem->waking++;
-	restore_flags(flags);
-}
-
-static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	save_flags(flags);
-	cli();
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	}
-	restore_flags(flags);
-	return ret;
-}
X 
X #include <asm/proc/semaphore.h>
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.2.7/linux/include/asm-arm/system.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/system.h	Sat May  8 11:07:16 1999
@@ -1,10 +1,26 @@
X #ifndef __ASM_ARM_SYSTEM_H
X #define __ASM_ARM_SYSTEM_H
X 
+#include <linux/kernel.h>
+
+#ifdef __KERNEL__
+
X #include <linux/config.h>
X 
+#define __ebsa285_data		__attribute__((__section__(".data.ebsa285")))
+#define __netwinder_data	__attribute__((__section__(".data.netwinder")))
+
+#ifdef CONFIG_TEXT_SECTIONS
+#define __ebsa285_text		__attribute__((__section__(".text.ebsa285")))
+#define __netwinder_text	__attribute__((__section__(".text.netwinder")))
+#else
+#define __ebsa285_text
+#define __netwinder_text
+#endif
+
X /* The type of machine we're running on */
-extern unsigned int machine_type;
+extern unsigned int __machine_arch_type;
+
X #define MACH_TYPE_EBSA110	0
X #define MACH_TYPE_RISCPC	1
X #define MACH_TYPE_NEXUSPCI	3
@@ -12,31 +28,101 @@
X #define MACH_TYPE_NETWINDER	5
X #define MACH_TYPE_CATS		6
X #define MACH_TYPE_TBOX		7
+#define MACH_TYPE_CO285		8
+#define MACH_TYPE_CLPS7110	9
+#define MACH_TYPE_ARCHIMEDES	10
+#define MACH_TYPE_A5K		11
+
+/*
+ * Sort out a definition for machine_arch_type
+ * The rules basically are:
+ * 1. If one architecture is selected, then all machine_is_xxx()
+ *    are constant.
+ * 2. If two or more architectures are selected, then the selected
+ *    machine_is_xxx() are variable, and the unselected machine_is_xxx()
+ *    are constant zero.
+ */
+#ifdef CONFIG_ARCH_EBSA110
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_EBSA110
+# endif
+# define machine_is_ebsa110()	(machine_arch_type == MACH_TYPE_EBSA110)
+#else
+# define machine_is_ebsa110()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_RPC
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_RISCPC
+# endif
+# define machine_is_riscpc()	(machine_arch_type == MACH_TYPE_RISCPC)
+#else
+# define machine_is_riscpc()	(0)
+#endif
X 
X #ifdef CONFIG_ARCH_EBSA285
-#define machine_is_ebsa285()	(1)
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_EBSA285
+# endif
+# define machine_is_ebsa285()	(machine_arch_type == MACH_TYPE_EBSA285)
X #else
-#define machine_is_ebsa285()	(0)
+# define machine_is_ebsa285()	(0)
X #endif
X 
-#ifdef CONFIG_ARCH_VNC
-#define machine_is_netwinder()	(1)
+#ifdef CONFIG_ARCH_NETWINDER
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_NETWINDER
+# endif
+# define machine_is_netwinder()	(machine_arch_type == MACH_TYPE_NETWINDER)
X #else
-#define machine_is_netwinder()	(0)
+# define machine_is_netwinder()	(0)
X #endif
X 
-#if defined(CONFIG_CATS)
-#define machine_is_cats()	(machine_type == MACH_TYPE_CATS)
+#ifdef CONFIG_CATS
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_CATS
+# endif
+# define machine_is_cats()	(machine_arch_type == MACH_TYPE_CATS)
X #else
-#define machine_is_cats()	(0)
+# define machine_is_cats()	(0)
X #endif
X 
-#if 0
-#define machine_is_ebsa285()	(machine_type == MACH_TYPE_EBSA285)
-#define machine_is_netwinder()	(machine_type == MACH_TYPE_NETWINDER)
+#ifdef CONFIG_ARCH_CO285
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_CO285
+# endif
+# define machine_is_co285()	(machine_arch_type == MACH_TYPE_CO285)
+#else
+# define machine_is_co285()	(0)
X #endif
X 
-#include <linux/kernel.h>
+#ifndef machine_arch_type
+#define machine_arch_type	__machine_arch_type
+#endif
+
+/*
+ * task_struct isn't always declared - forward-declare it here.
+ */
+struct task_struct;
+
X #include <asm/proc-fns.h>
X 
X extern void arm_malalignedptr(const char *, void *, volatile void *);
@@ -53,7 +139,7 @@
X  *
X  * `next' and `prev' should be struct task_struct, but it isn't always defined
X  */
-#define switch_to(prev,next) processor._switch_to(prev,next)
+#define switch_to(prev,next,last) do { last = processor._switch_to(prev,next); } while (0)
X 
X /*
X  * Include processor dependent parts
@@ -62,9 +148,12 @@
X #include <asm/arch/system.h>
X 
X #define mb() __asm__ __volatile__ ("" : : : "memory")
-#define nop() __asm__ __volatile__("mov r0,r0\n\t");
+#define rmb() mb()
+#define wmb() mb()
+#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
X 
X extern asmlinkage void __backtrace(void);
X 
X #endif
X 
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.2.7/linux/include/asm-arm/unistd.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/unistd.h	Sat May  8 11:06:58 1999
@@ -195,6 +195,9 @@
X #define __NR_capset			(__NR_SYSCALL_BASE+185)
X #define __NR_sigaltstack		(__NR_SYSCALL_BASE+186)
X #define __NR_sendfile			(__NR_SYSCALL_BASE+187)
+					/* 188 reserved */
+					/* 189 reserved */
+#define __NR_vfork			(__NR_SYSCALL_BASE+190)
X 
X #define __sys2(x) #x
X #define __sys1(x) __sys2(x)
@@ -364,7 +367,7 @@
X 
X static inline int _exit(int exitcode)
X {
-	extern int sys_exit(int);
+	extern int sys_exit(int) __attribute__((noreturn));
X 	return sys_exit(exitcode);
X }
X 
@@ -393,37 +396,11 @@
X static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp);
X 
X /*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
+ * Create a new kernel thread
X  */
-static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	long retval;
-
-	__asm__ __volatile__("
-	mov	r0,%1
-	mov	r1,%2
-	"__syscall(clone)"
-	teq	r0, #0
-	bne	1f
-	mov	r0,%4
-	mov	lr, pc
-	mov	pc, %3
-	"__syscall(exit)"
-1:	mov %0,r0"
-        : "=r" (retval)
-        : "Ir" (flags | CLONE_VM), "Ir" (NULL), "r" (fn), "Ir" (arg)
-	: "r0","r1","r2","r3","lr");
-	
-	return retval;
-}
+extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
X 
X #endif
-
X #endif /* __ASM_ARM_UNISTD_H */
X 
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/vga.h linux/include/asm-arm/vga.h
--- v2.2.7/linux/include/asm-arm/vga.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/vga.h	Sat May  8 11:06:58 1999
@@ -1,9 +1,10 @@
X #ifndef ASMARM_VGA_H
X #define ASMARM_VGA_H
X 
+#include <asm/hardware.h>
X #include <asm/io.h>
X 
-#define VGA_MAP_MEM(x)	(0xe0000000 + (x))
+#define VGA_MAP_MEM(x)	(PCIMEM_BASE + (x))
X 
X #define vga_readb(x)	(*(x))
X #define vga_writeb(x,y)	(*(y) = (x))
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.2.7/linux/include/asm-i386/bugs.h	Fri Jan  1 12:58:21 1999
+++ linux/include/asm-i386/bugs.h	Tue May 11 10:35:39 1999
@@ -19,6 +19,7 @@
X 
X #include <linux/config.h>
X #include <asm/processor.h>
+#include <asm/msr.h>
X 
X #define CONFIG_BUGi386
X 
@@ -27,6 +28,11 @@
X 	boot_cpu_data.hlt_works_ok = 0;
X }
X 
+__initfunc(static void mca_pentium(char *s, int *ints))
+{
+	mca_pentium_flag = 1;
+}
+
X __initfunc(static void no_387(char *s, int *ints))
X {
X 	boot_cpu_data.hard_math = 0;
@@ -61,6 +67,31 @@
X #endif
X 		return;
X 	}
+	if (mca_pentium_flag) {
+		/* The IBM Model 95 machines with pentiums lock up on
+		 * fpu test, so we avoid it. All pentiums have inbuilt
+		 * FPU and thus should use exception 16. We still do
+		 * the FDIV test, although I doubt there where ever any
+		 * MCA boxes built with non-FDIV-bug cpus.
+		 */
+		__asm__("fninit\n\t"
+			"fldl %1\n\t"
+			"fdivl %2\n\t"
+			"fmull %2\n\t"
+			"fldl %1\n\t"
+			"fsubp %%st,%%st(1)\n\t"
+			"fistpl %0\n\t"
+			"fwait\n\t"
+			"fninit"
+			: "=m" (*&boot_cpu_data.fdiv_bug)
+			: "m" (*&x), "m" (*&y));
+		printk("mca-pentium specified, avoiding FPU coupling test... ");
+		if (!boot_cpu_data.fdiv_bug)
+			printk("??? No FDIV bug? Lucky you...\n");
+		else
+			printk("detected FDIV bug though.\n");
+		return;
+	}
X 	/*
X 	 * check if exception 16 works correctly.. This is truly evil
X 	 * code: it disables the high 8 interrupts to make sure that
@@ -173,10 +204,10 @@
X 
X 		n = K6_BUG_LOOP;
X 		f_vide = vide;
-		__asm__ ("rdtsc" : "=a" (d));
+		rdtscl(d);
X 		while (n--) 
X 			f_vide();
-		__asm__ ("rdtsc" : "=a" (d2));
+		rdtscl(d2);
X 		d = d2-d;
X 
X 		/* Knock these two lines out if it debugs out ok */
@@ -246,6 +277,7 @@
X 	    ((Cx86_dir0_msb == 5) || (Cx86_dir0_msb == 3))) {
X 		int eax, dummy;
X 		unsigned char ccr3, ccr4;
+		__u32 old_cap;
X 
X 		cli();
X 		ccr3 = getCx86(CX86_CCR3);
@@ -257,8 +289,11 @@
X 
X 		/* we have up to level 1 available on the Cx6x86(L|MX) */
X 		boot_cpu_data.cpuid_level = 1;
+		/*  Need to preserve some externally computed capabilities  */
+		old_cap = boot_cpu_data.x86_capability & X86_FEATURE_MTRR;
X 		cpuid(1, &eax, &dummy, &dummy,
X 		      &boot_cpu_data.x86_capability);
+		boot_cpu_data.x86_capability |= old_cap;
X 
X 		boot_cpu_data.x86 = (eax >> 8) & 15;
X 		/*
@@ -314,6 +349,24 @@
X }
X  
X /*
+ * In setup.c's cyrix_model() we have set the boot_cpu_data.coma_bug
+ * on certain processors that we know contain this bug and now we
+ * enable the workaround for it.
+ */
+
+__initfunc(static void check_cyrix_coma(void))
+{
+	if (boot_cpu_data.coma_bug) {
+		unsigned char ccr1;
+		cli();
+		ccr1 = getCx86 (CX86_CCR1);
+		setCx86 (CX86_CCR1, ccr1 | 0x10);
+		sti();
+		printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
+	}
+}
+ 
+/*
X  * Check wether we are able to run this kernel safely on SMP.
X  *
X  * - In order to run on a i386, we need to be compiled for i386
@@ -371,5 +424,6 @@
X 	check_popad();
X 	check_amd_k6();
X 	check_pentium_f00f();
+	check_cyrix_coma();
X 	system_utsname.machine[1] = '0' + boot_cpu_data.x86;
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.2.7/linux/include/asm-i386/irq.h	Tue Feb 23 15:21:34 1999
+++ linux/include/asm-i386/irq.h	Thu May  6 14:02:34 1999
@@ -29,6 +29,7 @@
X }
X 
X extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
X extern void enable_irq(unsigned int);
X 
X #endif /* _ASM_IRQ_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/msr.h linux/include/asm-i386/msr.h
--- v2.2.7/linux/include/asm-i386/msr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/msr.h	Thu Apr 29 11:53:41 1999
@@ -0,0 +1,30 @@
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+			    : "=a" (val1), "=d" (val2) \
+			    : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+			  : /* no outputs */ \
+			  : "c" (msr), "a" (val1), "d" (val2))
+
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+     __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) \
+     __asm__ __volatile__ ("rdtsc" : "=A" (val))
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+			  : "=a" (low), "=d" (high) \
+			  : "c" (counter))
+
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/mtrr.h linux/include/asm-i386/mtrr.h
--- v2.2.7/linux/include/asm-i386/mtrr.h	Mon Oct  5 13:13:42 1998
+++ linux/include/asm-i386/mtrr.h	Tue May 11 10:37:16 1999
@@ -1,6 +1,6 @@
X /*  Generic MTRR (Memory Type Range Register) ioctls.
X 
-    Copyright (C) 1997-1998  Richard Gooch
+    Copyright (C) 1997-1999  Richard Gooch
X 
X     This library is free software; you can redistribute it and/or
X     modify it under the terms of the GNU Library General Public
@@ -44,10 +44,11 @@
X };
X 
X /*  These are the various ioctls  */
-#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry)
-#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry)
-#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry)
+#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry)
+#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry)
+#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry)
X #define MTRRIOC_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
+#define MTRRIOC_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry)
X 
X /*  These are the region types  */
X #define MTRR_TYPE_UNCACHABLE 0
@@ -75,7 +76,7 @@
X #ifdef __KERNEL__
X 
X /*  The following functions are for use by other drivers  */
-# if defined(CONFIG_MTRR) || defined(CONFIG_MTRR_MODULE)
+# ifdef CONFIG_MTRR
X extern int mtrr_add (unsigned long base, unsigned long size,
X 		     unsigned int type, char increment);
X extern int mtrr_del (int reg, unsigned long base, unsigned long size);
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.2.7/linux/include/asm-i386/processor.h	Tue Jan 19 11:32:53 1999
+++ linux/include/asm-i386/processor.h	Tue May 11 10:35:44 1999
@@ -35,6 +35,7 @@
X 				    call  */
X 	int	fdiv_bug;
X 	int	f00f_bug;
+	int	coma_bug;
X 	unsigned long loops_per_sec;
X 	unsigned long *pgd_quick;
X 	unsigned long *pte_quick;
@@ -119,12 +120,17 @@
X /*
X  *      Cyrix CPU configuration register indexes
X  */
+#define CX86_CCR0 0xc0
+#define CX86_CCR1 0xc1
X #define CX86_CCR2 0xc2
X #define CX86_CCR3 0xc3
X #define CX86_CCR4 0xe8
X #define CX86_CCR5 0xe9
+#define CX86_CCR6 0xea
X #define CX86_DIR0 0xfe
X #define CX86_DIR1 0xff
+#define CX86_ARR_BASE 0xc4
+#define CX86_RCR_BASE 0xdc
X 
X /*
X  *      Cyrix CPU indexed register access macros
@@ -148,6 +154,7 @@
X extern unsigned int machine_id;
X extern unsigned int machine_submodel_id;
X extern unsigned int BIOS_revision;
+extern unsigned int mca_pentium_flag;
X 
X /*
X  * User space process size: 3GB (default).
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.2.7/linux/include/asm-i386/system.h	Mon Dec 28 15:00:53 1998
+++ linux/include/asm-i386/system.h	Tue May 11 10:35:42 1999
@@ -9,30 +9,24 @@
X struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
X extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
X 
-/*
- * We do most of the task switching in C, but we need
- * to do the EIP/ESP switch in assembly..
- */
-#define switch_to(prev,next) do {					\
-	unsigned long eax, edx, ecx;					\
-	asm volatile("pushl %%ebx\n\t"					\
-		     "pushl %%esi\n\t"					\
+#define switch_to(prev,next,last) do {					\
+	asm volatile("pushl %%esi\n\t"					\
X 		     "pushl %%edi\n\t"					\
X 		     "pushl %%ebp\n\t"					\
X 		     "movl %%esp,%0\n\t"	/* save ESP */		\
-		     "movl %5,%%esp\n\t"	/* restore ESP */	\
+		     "movl %3,%%esp\n\t"	/* restore ESP */	\
X 		     "movl $1f,%1\n\t"		/* save EIP */		\
-		     "pushl %6\n\t"		/* restore EIP */	\
+		     "pushl %4\n\t"		/* restore EIP */	\
X 		     "jmp __switch_to\n"				\
X 		     "1:\t"						\
X 		     "popl %%ebp\n\t"					\
X 		     "popl %%edi\n\t"					\
X 		     "popl %%esi\n\t"					\
-		     "popl %%ebx"					\
X 		     :"=m" (prev->tss.esp),"=m" (prev->tss.eip),	\
-		      "=a" (eax), "=d" (edx), "=c" (ecx)		\
+		      "=b" (last)					\
X 		     :"m" (next->tss.esp),"m" (next->tss.eip),		\
-		      "a" (prev), "d" (next)); 				\
+		      "a" (prev), "d" (next),				\
+		      "b" (prev));					\
X } while (0)
X 
X #define _set_base(addr,base) do { unsigned long __pr; \
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/timex.h linux/include/asm-i386/timex.h
--- v2.2.7/linux/include/asm-i386/timex.h	Mon Mar 29 11:09:12 1999
+++ linux/include/asm-i386/timex.h	Tue May 11 10:35:42 1999
@@ -7,6 +7,7 @@
X #define _ASMi386_TIMEX_H
X 
X #include <linux/config.h>
+#include <asm/msr.h>
X 
X #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
X #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
@@ -39,7 +40,7 @@
X #else
X 	unsigned long eax, edx;
X 
-	__asm__ __volatile__("rdtsc":"=a" (eax), "=d" (edx));
+	rdtsc(eax,edx);
X 	return eax;
X #endif
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/atari_SCCserial.h linux/include/asm-m68k/atari_SCCserial.h
--- v2.2.7/linux/include/asm-m68k/atari_SCCserial.h	Tue Jun 23 10:01:28 1998
+++ linux/include/asm-m68k/atari_SCCserial.h	Tue May 11 09:57:14 1999
@@ -28,6 +28,8 @@
X #define SCC_BAUD_BASE_NONE	0		/* for not connected or unused
X 						 * clock sources */
X 
+#define SCC_BAUD_BASE_M147_PCLK	312500	/* 5 MHz */
+#define SCC_BAUD_BASE_M147	312500	/* 5 MHz */
X #define SCC_BAUD_BASE_MVME_PCLK	781250	/* 12.5 MHz */
X #define SCC_BAUD_BASE_MVME	625000	/* 10.000 MHz */
X #define SCC_BAUD_BASE_BVME_PCLK	781250	/* 12.5 MHz */   /* XXX ??? */
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- v2.2.7/linux/include/asm-m68k/bootinfo.h	Wed Jan 20 23:14:06 1999
+++ linux/include/asm-m68k/bootinfo.h	Tue May 11 09:57:14 1999
@@ -219,9 +219,10 @@
X #define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
X #define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
X #define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define MVME147_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
X #define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
X #define BVME6000_BOOTI_VERSION MK_BI_VERSION( 2, 0 )
-
+#define Q40_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
X 
X #ifdef BOOTINFO_COMPAT_1_0
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/dvma.h linux/include/asm-m68k/dvma.h
--- v2.2.7/linux/include/asm-m68k/dvma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/dvma.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,165 @@
+/* $Id: dvma.h,v 1.4 1999/03/27 20:23:41 tsbogend Exp $
+ * include/asm-m68k/dma.h
+ *
+ * Copyright 1995 (C) David S. Miller (da...@caip.rutgers.edu)
+ * 
+ * Hacked to fit Sun3x needs by Thomas Bogendoerfer
+ */
+
+#ifndef __M68K_DVMA_H
+#define __M68K_DVMA_H
+
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+  __volatile__ unsigned long cond_reg;	/* DMA condition register */
+  __volatile__ unsigned long st_addr;	/* Start address of this transfer */
+  __volatile__ unsigned long  cnt;	/* How many bytes to transfer */
+  __volatile__ unsigned long dma_test;	/* DMA test register */
+};
+
+/* DVMA chip revisions */
+enum dvma_rev {
+	dvmarev0,
+	dvmaesc1,
+	dvmarev1,
+	dvmarev2,
+	dvmarev3,
+	dvmarevplus,
+	dvmahme
+};
+
+#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
+
+/* Linux DMA information structure, filled during probe. */
+struct Linux_SBus_DMA {
+	struct Linux_SBus_DMA *next;
+	struct linux_sbus_device *SBus_dev;
+	struct sparc_dma_registers *regs;
+
+	/* Status, misc info */
+	int node;                /* Prom node for this DMA device */
+	int running;             /* Are we doing DMA now? */
+	int allocated;           /* Are we "owned" by anyone yet? */
+
+	/* Transfer information. */
+	unsigned long addr;      /* Start address of current transfer */
+	int nbytes;              /* Size of current transfer */
+	int realbytes;           /* For splitting up large transfers, etc. */
+
+	/* DMA revision */
+	enum dvma_rev revision;
+};
+
+extern struct Linux_SBus_DMA *dma_chain;
+
+/* Broken hardware... */
+#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
+#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURST8	 0x00040000	   /* ENET: SBUS r/w burst size */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* Determine highest possible final transfer address given a base */
+#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
+
+/* Yes, I hack a lot of elisp in my spare time... */
+#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
+#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
+#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
+#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
+#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
+#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
+#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
+#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
+#define DMA_BEGINDMA_W(regs) \
+        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
+#define DMA_BEGINDMA_R(regs) \
+        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
+
+/* For certain DMA chips, we need to disable ints upon irq entry
+ * and turn them back on when we are done.  So in any ESP interrupt
+ * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
+ * when leaving the handler.  You have been warned...
+ */
+#define DMA_IRQ_ENTRY(dma, dregs) do { \
+        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
+   } while (0)
+
+#define DMA_IRQ_EXIT(dma, dregs) do { \
+	if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
+   } while(0)
+
+/* Reset the friggin' thing... */
+#define DMA_RESET(dma) do { \
+	struct sparc_dma_registers *regs = dma->regs;                      \
+	/* Let the current FIFO drain itself */                            \
+	sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
+	/* Reset the logic */                                              \
+	regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
+	__delay(400);                         /* let the bits set ;) */    \
+	regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
+	sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
+	/* Enable FAST transfers if available */                           \
+	if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
+	dma->running = 0;                                                  \
+} while(0)
+
+extern unsigned long dvma_alloc (unsigned long, unsigned long);
+extern void dvma_free (unsigned long, unsigned long);
+
+#endif /* !(__M68K_DVMA_H) */
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/floppy.h linux/include/asm-m68k/floppy.h
--- v2.2.7/linux/include/asm-m68k/floppy.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/floppy.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,239 @@
+/*
+ * Q40 Architecture specific parts of the Floppy driver
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999
+ */
+
+#include <asm/io.h>
+
+#include <linux/vmalloc.h>
+
+
+asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs);
+
+#define MAX_DMA_ADDRESS   0x00  /* nothing like that */
+
+extern spinlock_t  dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+	unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 29'
echo 'File patch-2.2.8 is continued in part 30'
echo 30 > _shar_seq_.tmp
#!/bin/sh
# this is part 30 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 30; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+	return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+
+
+
+#define fd_inb(port)			inb_p(port)
+#define fd_outb(port,value)		outb_p(port,value)
+
+
+#define fd_request_dma()        vdma_request_dma(FLOPPY_DMA,"floppy")
+/*#define fd_free_dma()           */
+
+
+#define fd_get_dma_residue()    vdma_get_dma_residue(FLOPPY_DMA)
+#define fd_dma_mem_alloc(size)	vdma_mem_alloc(size)
+#define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
+
+
+#define fd_enable_irq()           /* nothing... */
+#define fd_disable_irq()          /* nothing... */
+#define fd_free_irq()		free_irq(FLOPPY_IRQ, NULL)
+
+#define fd_free_dma()             /* nothing */
+
+/* No 64k boundary crossing problems on Q40 - no DMA at all */
+#define CROSS_64KB(a,s) (0)
+
+#define DMA_MODE_READ  0x44    /* i386 look-alike */
+#define DMA_MODE_WRITE 0x48
+
+
+static int q40_floppy_init(void)
+{
+  use_virtual_dma =1;
+  /* FLOPPY_IRQ=6; */
+
+  if (MACH_IS_Q40)  
+    return 0x3f0;
+  else
+    return -1;
+}
+
+
+
+
+/*
+ * Again, the CMOS information doesn't work on the Q40..
+ */
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
+
+
+
+
+#define FLOPPY_MOTOR_MASK 0xf0
+
+
+
+
+/* basically PC init + set use_virtual_dma */
+#define  FDC1 q40_floppy_init()
+static int FDC2 = -1;
+
+
+#define N_FDC 1
+#define N_DRIVE 8
+
+
+
+/* vdma stuff adapted from asm-i386/floppy.h */
+
+static int virtual_dma_count=0;
+static int virtual_dma_residue=0;
+static char *virtual_dma_addr=0;
+static int virtual_dma_mode=0;
+static int doing_pdma=0;
+
+
+
+static int fd_request_irq(void)
+{
+  return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT,
+						   "floppy", NULL);
+}
+
+/*#define SLOW_DOWN do{outb(0,0x80);}while(0)*/
+#define SLOW_DOWN do{int count=1;do{if(!jiffies)break;}while(count-->0);}while(0)
+
+asmlinkage void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+	register unsigned char st;
+
+#undef TRACE_FLPY_INT
+#define NO_FLOPPY_ASSEMBLER
+
+#ifdef TRACE_FLPY_INT 
+	static int calls=0;
+	static int bytes=0;
+	static int dma_wait=0;
+#endif
+	if(!doing_pdma) {
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+
+#ifdef TRACE_FLPY_INT
+	if(!calls)
+		bytes = virtual_dma_count;
+#endif
+
+	{
+		register int lcount;
+		register char *lptr;
+
+		/* serve 1st byte fast: */
+
+		st=1;
+		for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 
+		    lcount; lcount--, lptr++) {
+			st=inb(virtual_dma_port+4) & 0xa0 ;
+			if(st != 0xa0) 
+				break;
+			if(virtual_dma_mode)
+				outb_p(*lptr, virtual_dma_port+5);
+			else
+				*lptr = inb_p(virtual_dma_port+5);
+		}
+
+		virtual_dma_count = lcount;
+		virtual_dma_addr = lptr;
+		st = inb(virtual_dma_port+4);
+	}
+
+#ifdef TRACE_FLPY_INT
+	calls++;
+#endif
+	if(st == 0x20)
+		return;
+	if(!(st & 0x20)) {
+		virtual_dma_residue += virtual_dma_count;
+		virtual_dma_count=0;
+#ifdef TRACE_FLPY_INT
+		printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 
+		       virtual_dma_count, virtual_dma_residue, calls, bytes,
+		       dma_wait);
+		calls = 0;
+		dma_wait=0;
+#endif
+		doing_pdma = 0;
+		floppy_interrupt(irq, dev_id, regs);
+		return;
+	}
+#ifdef TRACE_FLPY_INT
+	if(!virtual_dma_count)
+		dma_wait++;
+#endif
+}
+
+
+
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+	return 0;
+}
+
+
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+	return virtual_dma_count + virtual_dma_residue;
+}
+
+
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+	return (unsigned long) vmalloc(size);
+
+}
+
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+        vfree((void *)addr);
+}
+#define fd_dma_mem_free(addr,size) _fd_dma_mem_free(addr, size)
+
+
+/* choose_dma_mode ???*/
+
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+	doing_pdma = 1;
+	virtual_dma_port = io;
+	virtual_dma_mode = (mode  == DMA_MODE_WRITE);
+	virtual_dma_addr = addr;
+	virtual_dma_count = size;
+	virtual_dma_residue = 0;
+	return 0;
+}
+
+
+
+static void fd_disable_dma(void)
+{
+	doing_pdma = 0;
+	virtual_dma_residue += virtual_dma_count;
+	virtual_dma_count=0;
+}
+
+
+
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.2.7/linux/include/asm-m68k/ide.h	Wed Jan 20 23:14:06 1999
+++ linux/include/asm-m68k/ide.h	Tue May 11 09:57:14 1999
@@ -45,22 +45,38 @@
X #include <asm/macints.h>
X #endif
X 
+
+typedef unsigned int   q40ide_ioreg_t;
+
+
X typedef unsigned char * ide_ioreg_t;
X 
+
X #ifndef MAX_HWIFS
X #define MAX_HWIFS	4	/* same as the other archs */
X #endif
X 
-static __inline int ide_default_irq (ide_ioreg_t base)
+int q40ide_default_irq(q40ide_ioreg_t);
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
X {
-	return 0;
+        if (MACH_IS_Q40)
+	      return q40ide_default_irq((q40ide_ioreg_t) base);
+	else return 0;
X }
X 
+
X /*
X  *  Can we do this in a generic manner??
X  */
+void q40_ide_init_hwif_ports (q40ide_ioreg_t *p, q40ide_ioreg_t base, int *irq);
+
X static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
X {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+      return q40_ide_init_hwif_ports((q40ide_ioreg_t *)p,(q40ide_ioreg_t)base,irq);
+#endif
X     printk("ide_init_hwif_ports: must not be called\n");
X }
X 
@@ -86,6 +102,10 @@
X 	if (MACH_IS_AMIGA)
X 		return request_irq(irq, handler, 0, device, dev_id);
X #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+	  	return request_irq(irq, handler, 0, device, dev_id);
+#endif /* CONFIG_Q40*/
X #ifdef CONFIG_MAC
X 	if (MACH_IS_MAC)
X #if 0	/* MSch Hack: maybe later we'll call ide_intr without a wrapper */
@@ -103,6 +123,10 @@
X 	if (MACH_IS_AMIGA)
X 		free_irq(irq, dev_id);
X #endif /* CONFIG_AMIGA */
+#ifdef CONFIG_Q40
+	if (MACH_IS_Q40)
+	  	free_irq(irq, dev_id);
+#endif /* CONFIG_Q40*/
X #ifdef CONFIG_MAC
X 	if (MACH_IS_MAC)
X 		nubus_free_irq(12);
@@ -119,10 +143,18 @@
X 
X static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
X {
+#ifdef CONFIG_Q40
+        if (MACH_IS_Q40)
+            request_region((q40ide_ioreg_t)from,extent,name);
+#endif
X }
X 
X static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
X {
+#ifdef CONFIG_Q40
+        if (MACH_IS_Q40)
+            release_region((q40ide_ioreg_t)from,extent);
+#endif
X }
X 
X #undef SUPPORT_SLOW_DATA_PORTS
@@ -131,14 +163,36 @@
X #undef SUPPORT_VLB_SYNC
X #define SUPPORT_VLB_SYNC 0
X 
+/* this definition is used only on startup .. */
+#ifndef CONFIG_Q40
X #undef HD_DATA
X #define HD_DATA NULL
+#else
+#ifdef MACH_Q40_ONLY
+#undef HD_DATA
+#define HD_DATA ((ide_ioreg_t)0x1f0)
+#else
+#undef HD_DATA
+#define HD_DATA   (MACH_IS_Q40 ? (ide_ioreg_t)0x1f0 : 0)
+#endif
+#endif
+
X 
X #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
X #define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
X 
+#ifdef CONFIG_Q40
+#ifdef MACH_Q40_ONLY
+#define ADDR_TRANS(_addr_) (Q40_ISA_IO_W(_addr_))
+#else
+#define ADDR_TRANS(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
+#endif
+#else
+#define ADDR_TRANS(_addr_) (_addr_)
+#endif
+
X #define insw(port, buf, nr) ({				\
-	unsigned char *_port = (unsigned char *)(port);	\
+	unsigned char *_port = (unsigned char *) ADDR_TRANS(port);	\
X 	unsigned char *_buf = (buf);			\
X 	int _nr = (nr);					\
X 	unsigned long _tmp;				\
@@ -179,7 +233,7 @@
X })
X 
X #define outsw(port, buf, nr) ({				\
-	unsigned char *_port = (unsigned char *)(port);	\
+	unsigned char *_port = (unsigned char *) ADDR_TRANS(port);	\
X 	unsigned char *_buf = (buf);			\
X 	int _nr = (nr);					\
X 	unsigned long _tmp;				\
@@ -219,7 +273,7 @@
X 	}						\
X })
X 
-#ifdef CONFIG_ATARI
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
X #define insl_swapw(data_reg, buffer, wcount) \
X     insw_swapw(data_reg, buffer, (wcount)<<1)
X #define outsl_swapw(data_reg, buffer, wcount) \
@@ -236,7 +290,7 @@
X 		 rolw  #8,%/d0; \
X 		 movew %/d0,%/a1@+; \
X 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
X 		: "d0", "a0", "a1", "d6"); \
X     else \
X 	__asm__ __volatile__ \
@@ -270,8 +324,9 @@
X 		 rolw  #8,%/d0; \
X 		 movew %/d0,%/a1@+; \
X 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
-		: "d0", "a0", "a1", "d6")
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
+		: "d0", "a0", "a1", "d6") 
+
X 
X #define outsw_swapw(port, buf, nr) \
X     if ((nr) % 8) \
@@ -284,7 +339,7 @@
X 		 rolw  #8,%/d0; \
X 		 movew %/d0,%/a0@; \
X 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
X 		: "d0", "a0", "a1", "d6"); \
X     else \
X 	__asm__ __volatile__ \
@@ -318,7 +373,7 @@
X 		 rolw  #8,%/d0; \
X 		 movew %/d0,%/a0@; \
X 		 dbra %/d6,1b" : \
-		: "g" (port), "g" (buf), "g" (nr) \
+		: "g" (ADDR_TRANS(port)), "g" (buf), "g" (nr) \
X 		: "d0", "a0", "a1", "d6")
X 
X #endif /* CONFIG_ATARI */
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/keyboard.h linux/include/asm-m68k/keyboard.h
--- v2.2.7/linux/include/asm-m68k/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-m68k/keyboard.h	Tue May 11 09:57:14 1999
@@ -16,26 +16,46 @@
X 
X #include <asm/machdep.h>
X 
+#ifdef CONFIG_Q40
+#include <asm/q40_keyboard.h>
+#endif
+
X static __inline__ int kbd_setkeycode(unsigned int scancode,
X 				     unsigned int keycode)
X {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_setkeycode(scancode,keycode);
+#endif
X     return -EOPNOTSUPP;
X }
X 
X static __inline__ int kbd_getkeycode(unsigned int scancode)
X {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_getkeycode(scancode);
+#endif
X     return scancode > 127 ? -EINVAL : scancode;
X }
X 
X static __inline__ int kbd_translate(unsigned char scancode,
X 				    unsigned char *keycode, char raw_mode)
X {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_translate(scancode,keycode,raw_mode);
+#endif
X     *keycode = scancode;
X     return 1;
X }
X 
X static __inline__ char kbd_unexpected_up(unsigned char keycode)
X {
+#ifdef CONFIG_Q40
+    if (MACH_IS_Q40)
+        return q40kbd_unexpected_up(keycode);
+#endif
X     return 0200;
X }
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/mvme147hw.h linux/include/asm-m68k/mvme147hw.h
--- v2.2.7/linux/include/asm-m68k/mvme147hw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mvme147hw.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,110 @@
+#ifndef _MVME147HW_H_
+#define _MVME147HW_H_
+
+typedef struct {
+	unsigned char
+		ctrl,
+		bcd_sec,
+		bcd_min,
+		bcd_hr,
+		bcd_dow,
+		bcd_dom,
+		bcd_mth,
+		bcd_year;
+} MK48T02;
+
+#define RTC_WRITE	0x80
+#define RTC_READ	0x40
+#define RTC_STOP	0x20
+
+#define m147_rtc ((MK48T02 * volatile)0xfffe07f8)
+
+
+struct pcc_regs {
+   volatile u_long 	dma_tadr;
+   volatile u_long	dma_dadr;
+   volatile u_long	dma_bcr;
+   volatile u_long	dma_hr;
+   volatile u_short	t1_preload;
+   volatile u_short	t1_count;
+   volatile u_short	t2_preload;
+   volatile u_short	t2_count;
+   volatile u_char	t1_int_cntrl;
+   volatile u_char	t1_cntrl;
+   volatile u_char	t2_int_cntrl;
+   volatile u_char	t2_cntrl;
+   volatile u_char	ac_fail;
+   volatile u_char	watchdog;
+   volatile u_char	lpt_intr;
+   volatile u_char	lpt_cntrl;
+   volatile u_char	dma_intr;
+   volatile u_char	dma_cntrl;
+   volatile u_char	bus_error;
+   volatile u_char	dma_status;
+   volatile u_char	abort;
+   volatile u_char	ta_fnctl;
+   volatile u_char	serial_cntrl;
+   volatile u_char	general_cntrl;
+   volatile u_char	lan_cntrl;
+   volatile u_char	general_status;
+   volatile u_char	scsi_interrupt;
+   volatile u_char	slave;
+   volatile u_char	soft1_cntrl;
+   volatile u_char	int_base;
+   volatile u_char	soft2_cntrl;
+   volatile u_char	revision_level;
+   volatile u_char	lpt_data;
+   volatile u_char	lpt_status;
+   };
+
+#define m147_pcc ((struct pcc_regs * volatile)0xfffe1000)
+
+
+#define PCC_INT_ENAB		0x08
+
+#define PCC_TIMER_INT_CLR	0x80
+#define PCC_TIMER_PRELOAD	63936l
+
+#define PCC_LEVEL_ABORT		0x07
+#define PCC_LEVEL_SERIAL	0x04
+#define PCC_LEVEL_ETH		0x04
+#define PCC_LEVEL_TIMER1	0x04
+#define PCC_LEVEL_SCSI_PORT	0x04
+#define PCC_LEVEL_SCSI_DMA	0x04
+
+#define PCC_IRQ_AC_FAIL		0x40
+#define PCC_IRQ_BERR		0x41
+#define PCC_IRQ_ABORT		0x42
+/* #define PCC_IRQ_SERIAL	0x43 */
+#define PCC_IRQ_PRINTER		0x47
+#define PCC_IRQ_TIMER1		0x48
+#define PCC_IRQ_TIMER2		0x49
+#define PCC_IRQ_SOFTWARE1	0x4a
+#define PCC_IRQ_SOFTWARE2	0x4b
+
+
+#define M147_SCC_A_ADDR		0xfffe3002
+#define M147_SCC_B_ADDR		0xfffe3000
+
+#define MVME147_IRQ_SCSI_PORT	0x45
+#define MVME147_IRQ_SCSI_DMA	0x46
+
+/* SCC interrupts, for MVME162 */
+
+#define MVME147_IRQ_TYPE_PRIO	0
+#define MVME147_IRQ_SCC_BASE		0x60
+#define MVME147_IRQ_SCCB_TX		0x60
+#define MVME147_IRQ_SCCB_STAT		0x62
+#define MVME147_IRQ_SCCB_RX		0x64
+#define MVME147_IRQ_SCCB_SPCOND		0x66
+#define MVME147_IRQ_SCCA_TX		0x68
+#define MVME147_IRQ_SCCA_STAT		0x6a
+#define MVME147_IRQ_SCCA_RX		0x6c
+#define MVME147_IRQ_SCCA_SPCOND		0x6e
+
+#define MVME147_LANCE_BASE	0xfffe1800
+#define MVME147_LANCE_IRQ	0x44
+
+#define ETHERNET_ADDRESS 0xfffe0778
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/oplib.h linux/include/asm-m68k/oplib.h
--- v2.2.7/linux/include/asm-m68k/oplib.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/oplib.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,8 @@
+/*
+ * prototypes for dummy prom_* routines
+ */
+
+extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getbool(int node, char *prop);
+extern void prom_printf(char *fmt, ...);
+extern void prom_halt(void) __attribute__ ((noreturn));
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- v2.2.7/linux/include/asm-m68k/page.h	Wed Jan 20 23:14:06 1999
+++ linux/include/asm-m68k/page.h	Tue May 11 09:57:14 1999
@@ -110,7 +110,22 @@
X /* This handles the memory map.. */
X #define PAGE_OFFSET		0
X #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
-#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+/*
+ * A hacky workaround for the problems with mmap() of frame buffer
+ * memory in the lower 16MB physical memoryspace.
+ *
+ * This is a short term solution, we will have to deal properly
+ * with this in 2.3.x.
+ */
+extern inline void *__va(unsigned long physaddr)
+{
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA && (physaddr < 16*1024*1024))
+		return (void *)0xffffffff;
+	else
+#endif
+		return (void *)(physaddr+PAGE_OFFSET);
+}
X #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
X 
X #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.2.7/linux/include/asm-m68k/pgtable.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-m68k/pgtable.h	Tue May 11 09:57:14 1999
@@ -507,6 +507,7 @@
X 	if (tsk == current) {
X 		if (CPU_IS_040_OR_060)
X 			__asm__ __volatile__ (".chip 68040\n\t"
+					      "pflushan\n\t"
X 					      "movec %0,%%urp\n\t"
X 					      ".chip 68k"
X 					      : : "r" (tsk->tss.crp[1]));
@@ -514,10 +515,22 @@
X 			unsigned long tmp;
X 			__asm__ __volatile__ ("movec  %%cacr,%0\n\t"
X 					      "orw #0x0808,%0\n\t"
-					      "movec %0,%%cacr\n\t"
-					      "pmove %1,%%crp\n\t"
-					      : "=d" (tmp)
-					      : "m" (tsk->tss.crp[0]));
+					      "movec %0,%%cacr"
+					      : "=d" (tmp));
+			/* For a 030-only kernel, avoid flushing the whole
+			   ATC, we only need to flush the user entries.
+			   The 68851 does this by itself.  Avoid a runtime
+			   check here.  */
+			__asm__ __volatile__ (
+#ifdef CPU_M68030_ONLY
+					      ".chip 68030\n\t"
+					      "pmovefd %0,%%crp\n\t"
+					      ".chip 68k\n\t"
+					      "pflush #0,#4"
+#else
+					      "pmove %0,%%crp"
+#endif
+					      : : "m" (tsk->tss.crp[0]));
X 		}
X 	}
X }
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/q40_keyboard.h linux/include/asm-m68k/q40_keyboard.h
--- v2.2.7/linux/include/asm-m68k/q40_keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/q40_keyboard.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,54 @@
+/*
+ *  linux/include/asm-m68k/q40_keyboard.h
+ *
+ *  Created 
+ */
+
+/*
+ *  This file contains the Q40 specific keyboard definitions
+ */
+
+
+#include <linux/config.h> /* CONFIG_MAGIC_SYSRQ */
+
+
+
+#ifdef __KERNEL__
+
+
+#include <asm/machdep.h>
+
+
+
+extern int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int q40kbd_getkeycode(unsigned int scancode);
+extern int q40kbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char q40kbd_unexpected_up(unsigned char keycode);
+extern void q40kbd_leds(unsigned char leds);
+extern int q40kbd_is_sysrq(unsigned char keycode);
+extern void q40kbd_init_hw(void);
+extern unsigned char q40kbd_sysrq_xlate[128];
+
+
+#if 0
+#define kbd_setkeycode		q40kbd_setkeycode
+#define kbd_getkeycode		q40kbd_getkeycode
+#define kbd_pretranslate	q40kbd_pretranslate
+#define kbd_translate		q40kbd_translate
+#define kbd_unexpected_up	q40kbd_unexpected_up
+#define kbd_leds		q40kbd_leds
+#define kbd_init_hw		q40kbd_init_hw
+#define kbd_is_sysrq		q40kbd_is_sysrq
+#define kbd_sysrq_xlate		q40kbd_sysrq_xlate
+
+
+#define SYSRQ_KEY 0x54
+#endif
+#endif /* __KERNEL__ */
+
+
+
+
+
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/q40_master.h linux/include/asm-m68k/q40_master.h
--- v2.2.7/linux/include/asm-m68k/q40_master.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/q40_master.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,75 @@
+/* 
+ * Q40 master Chip Control 
+ * RTC stuff merged for compactnes..
+*/
+
+#if 1
+#define q40_master_addr 0xff000000
+#define q40_rtc_addr    0xff021ffc
+#else
+extern unsigned long q40_master_addr;  /* wherever it is mapped ... */
+extern unsigned long q40_rtc_addr;
+#endif
+
+#define IIRQ_REG            0x0       /* internal IRQ reg */
+#define EIRQ_REG            0x4       /* external ... */
+#define KEYCODE_REG         0x1c      /* value of received scancode  */
+#define DISPLAY_CONTROL_REG 0x18
+#define FRAME_CLEAR_REG     0x24
+
+#define INTERRUPT_REG       IIRQ_REG  /* "native" ints */
+#define KEY_IRQ_ENABLE_REG  0x08      /**/
+#define KEYBOARD_UNLOCK_REG 0x20      /* clear kb int */
+
+#define SAMPLE_ENABLE_REG   0x14      /* generate SAMPLE ints */
+#define SAMPLE_RATE_REG     0x28
+#define SAMPLE_CLEAR_REG    0x28
+#define SAMPLE_LOW          0x00
+#define SAMPLE_HIGH         0x01
+
+#define FRAME_RATE_REG       0x38      /* generate FRAME ints at 200 HZ rate */
+
+#if 0
+#define SER_ENABLE_REG      0x0c      /* allow serial ints to be generated */
+#endif
+#define EXT_ENABLE_REG      0x10      /* ... rest of the ISA ints ... */
+
+#define master_inb(_reg_)           (*(((unsigned char *)q40_master_addr)+_reg_))
+#define master_outb(_b_,_reg_)      (*(((unsigned char *)q40_master_addr)+_reg_)=(_b_))
+
+
+/* define some Q40 specific ints */
+#include "q40ints.h"
+
+/* RTC defines */
+
+#define Q40_RTC_BASE (q40_rtc_addr)
+
+#define RTC_YEAR        (*(unsigned char *)(Q40_RTC_BASE+0))
+#define RTC_MNTH        (*(unsigned char *)(Q40_RTC_BASE-4))
+#define RTC_DATE        (*(unsigned char *)(Q40_RTC_BASE-8))
+#define RTC_DOW         (*(unsigned char *)(Q40_RTC_BASE-12))
+#define RTC_HOUR        (*(unsigned char *)(Q40_RTC_BASE-16))
+#define RTC_MINS        (*(unsigned char *)(Q40_RTC_BASE-20))
+#define RTC_SECS        (*(unsigned char *)(Q40_RTC_BASE-24))
+#define RTC_CTRL        (*(unsigned char *)(Q40_RTC_BASE-28))
+
+
+#if 0
+struct RTC_STRUCT{ 
+  unsigned char bcd_year;
+  unsigned char bcd_mth;
+  unsigned char bcd_dom;
+  unsigned char bcd_dayofweek;
+  unsigned char bcd_hr;
+  unsigned char bcd_min;
+  unsigned char bcd_sec;
+  unsigned char ctrl;
+};
+typedef struct RTC_STRUCT *RtcPtr_t;
+#endif
+
+
+/* some control bits */
+#define RTC_READ   64  /* prepare for reading */
+#define RTC_WRITE  128
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/q40ints.h linux/include/asm-m68k/q40ints.h
--- v2.2.7/linux/include/asm-m68k/q40ints.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/q40ints.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,29 @@
+/*
+ * contains some Q40 related interrupt definitions
+ */
+
+#define Q40_IRQ_MAX      (34)
+
+#define Q40_IRQ_TIMER    (34)
+#define Q40_IRQ_KEYBOARD (32)
+#define Q40_IRQ_FRAME    (33)
+
+
+/* masks for interrupt regiosters*/
+/* internal, IIRQ_REG */
+#define IRQ_KEYB_MASK    (2)
+#define IRQ_SER_MASK     (1<<2)
+#define IRQ_FRAME_MASK   (1<<3)
+#define IRQ_EXT_MASK     (1<<4)    /* is a EIRQ */
+/* eirq, EIRQ_REG */
+#define IRQ3_MASK        (1)
+#define IRQ4_MASK        (1<<1)
+#define IRQ5_MASK        (1<<2)
+#define IRQ6_MASK        (1<<3)
+#define IRQ7_MASK        (1<<4)
+#define IRQ10_MASK       (1<<5)
+#define IRQ14_MASK       (1<<6)
+#define IRQ15_MASK       (1<<7)
+
+extern unsigned long q40_probe_irq_on (void);
+extern int q40_probe_irq_off (unsigned long irqs);
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/scatterlist.h linux/include/asm-m68k/scatterlist.h
--- v2.2.7/linux/include/asm-m68k/scatterlist.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/scatterlist.h	Tue May 11 09:57:14 1999
@@ -6,6 +6,14 @@
X     char * alt_address; /* Location of actual if address is a 
X 			 * dma indirect buffer.  NULL otherwise */
X     unsigned int length;
+    unsigned long dvma_address;
+};
+
+struct mmu_sglist {
+        char *addr;
+        char *__dont_touch;
+        unsigned int len;
+        unsigned long dvma_addr;
X };
X 
X /* This is bogus and should go away. */
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/semaphore-helper.h linux/include/asm-m68k/semaphore-helper.h
--- v2.2.7/linux/include/asm-m68k/semaphore-helper.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/semaphore-helper.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,136 @@
+#ifndef _M68K_SEMAPHORE_HELPER_H
+#define _M68K_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * m68k version by Andreas Schwab
+ */
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+ atomic_inc(&sem->waking);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	int ret;
+#ifndef CONFIG_RMW_INSNS
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 0;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+	int tmp1, tmp2;
+
+	__asm__ __volatile__
+	  ("1:	movel	%1,%2\n"
+	   "    jle	2f\n"
+	   "	subql	#1,%2\n"
+	   "	casl	%1,%2,%3\n"
+	   "	jne	1b\n"
+	   "	moveq	#1,%0\n"
+	   "2:"
+	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+	   : "m" (sem->waking), "0" (0), "1" (sem->waking));
+#endif
+
+	return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	int ret;
+#ifndef CONFIG_RMW_INSNS
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 0;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+	int tmp1, tmp2;
+
+	__asm__ __volatile__
+	  ("1:	movel	%1,%2\n"
+	   "	jle	2f\n"
+	   "	subql	#1,%2\n"
+	   "	casl	%1,%2,%3\n"
+	   "	jne	1b\n"
+	   "	moveq	#1,%0\n"
+	   "	jra	%a4\n"
+	   "2:"
+	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+	   : "m" (sem->waking), "i" (&&next), "0" (0), "1" (sem->waking));
+	if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+next:
+#endif
+
+	return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *	1	failed to lock
+ *	0	got the lock
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+	int ret;
+#ifndef CONFIG_RMW_INSNS
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 1;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 0;
+	} else
+		atomic_inc(&sem->count);
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+#else
+	int tmp1, tmp2;
+
+	__asm__ __volatile__
+	  ("1:	movel	%1,%2\n"
+	   "    jle	2f\n"
+	   "	subql	#1,%2\n"
+	   "	casl	%1,%2,%3\n"
+	   "	jne	1b\n"
+	   "	moveq	#0,%0\n"
+	   "2:"
+	   : "=d" (ret), "=d" (tmp1), "=d" (tmp2)
+	   : "m" (sem->waking), "0" (1), "1" (sem->waking));
+	if (ret)
+		atomic_inc(&sem->count);
+#endif
+	return ret;
+}
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.2.7/linux/include/asm-m68k/semaphore.h	Wed Jan 20 23:14:06 1999
+++ linux/include/asm-m68k/semaphore.h	Tue May 11 09:57:14 1999
@@ -3,9 +3,10 @@
X 
X #include <linux/config.h>
X #include <linux/linkage.h>
-#include <asm/current.h>
+
X #include <asm/system.h>
X #include <asm/atomic.h>
+#include <asm/spinlock.h>
X 
X /*
X  * SMP- and interrupt-safe semaphores..
@@ -17,79 +18,25 @@
X 
X struct semaphore {
X 	atomic_t count;
-	unsigned long owner, owner_depth;
X 	atomic_t waking;
X 	struct wait_queue * wait;
X };
X 
-/*
- * Because we want the non-contention case to be
- * fast, we save the stack pointer into the "owner"
- * field, and to get the true task pointer we have
- * to do the bit masking. That moves the masking
- * operation into the slow path.
- */
-#define semaphore_owner(sem) \
-	((struct task_struct *)((2*PAGE_MASK) & (sem)->owner))
-
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, 0, ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, 1, ATOMIC_INIT(0), NULL })
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
X 
X asmlinkage void __down_failed(void /* special register calling convention */);
X asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
X asmlinkage void __up_wakeup(void /* special register calling convention */);
X 
-extern void __down(struct semaphore * sem);
-extern int  __down_interruptible(struct semaphore * sem);
-extern void __up(struct semaphore * sem);
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
X 
X #define sema_init(sem, val)	atomic_set(&((sem)->count), val)
X 
-static inline void wake_one_more(struct semaphore * sem)
-{
- atomic_inc(&sem->waking);
-}
-
-static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
-{
-#ifndef CONFIG_RMW_INSNS
-	unsigned long flags;
-	int ret = 0;
-
-	save_flags(flags);
-	cli();
-	if (atomic_read(&sem->waking) > 0 || (owner_depth && semaphore_owner(sem) == tsk)) {
-		sem->owner = (unsigned long)tsk;
-		sem->owner_depth++;
-		atomic_dec(&sem->waking);
-		ret = 1;
-	}
-	restore_flags(flags);
-#else
-	int ret, tmp;
-
-	__asm__ __volatile__
-	  ("1:	movel	%2,%0\n"
-	   "    jeq	3f\n"
-	   "2:	movel	%0,%1\n"
-	   "	subql	#1,%1\n"
-	   "	casl	%0,%1,%2\n"
-	   "	jeq	3f\n"
-	   "	tstl	%0\n"
-	   "	jne	2b\n"
-	   "3:"
-	   : "=d" (ret), "=d" (tmp), "=m" (sem->waking));
-
-	ret |= ((sem->owner_depth != 0) && (semaphore_owner(sem) == tsk));
-	if (ret) {
-		sem->owner = (unsigned long)tsk;
-		sem->owner_depth++;
-	}
-
-#endif
-	return ret;
-}
-
X /*
X  * This is ugly, but we want the default case to fall through.
X  * "down_failed" is a special asm handler that calls the C
@@ -102,8 +49,6 @@
X 		"| atomic down operation\n\t"
X 		"subql #1,%0@\n\t"
X 		"jmi 2f\n\t"
-		"movel %%sp,4(%0)\n"
-		"movel #1,8(%0)\n\t"
X 		"1:\n"
X 		".section .text.lock,\"ax\"\n"
X 		".even\n"
@@ -124,9 +69,6 @@
X 		"| atomic interruptible down operation\n\t"
X 		"subql #1,%1@\n\t"
X 		"jmi 2f\n\t"
-		"movel %%sp,4(%1)\n"
-		"moveql #1,%0\n"
-		"movel %0,8(%1)\n"
X 		"clrl %0\n"
X 		"1:\n"
X 		".section .text.lock,\"ax\"\n"
@@ -140,6 +82,28 @@
X 	return result;
X }
X 
+extern inline int down_trylock(struct semaphore * sem)
+{
+	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+	register int result __asm__ ("%d0");
+
+	__asm__ __volatile__(
+		"| atomic down trylock operation\n\t"
+		"subql #1,%1@\n\t"
+		"jmi 2f\n\t"
+		"clrl %0\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		".even\n"
+		"2:\tpea 1b\n\t"
+		"jbra __down_failed_trylock\n"
+		".previous"
+		: "=d" (result)
+		: "a" (sem1)
+		: "%d0", "memory");
+	return result;
+}
+
X /*
X  * Note! This is subtle. We jump to wake people up only if
X  * the semaphore was negative (== somebody was waiting on it).
@@ -151,13 +115,13 @@
X 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
X 	__asm__ __volatile__(
X 		"| atomic up operation\n\t"
-		"subql #1,8(%0)\n\t"
X 		"addql #1,%0@\n\t"
X 		"jle 2f\n"
X 		"1:\n"
X 		".section .text.lock,\"ax\"\n"
X 		".even\n"
-		"2:\tpea 1b\n\t"
+		"2:\t"
+		"pea 1b\n\t"
X 		"jbra __up_wakeup\n"
X 		".previous"
X 		: /* no outputs */
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- v2.2.7/linux/include/asm-m68k/serial.h	Thu Nov 12 16:21:24 1998
+++ linux/include/asm-m68k/serial.h	Tue May 11 09:57:14 1999
@@ -1,448 +1,84 @@
X /*
- * include/linux/serial.h
+ * include/asm-m68k/serial.h
X  *
- * Copyright (C) 1992 by Theodore Ts'o.
- * 
- * Redistribution of this file is permitted under the terms of the GNU 
- * Public License (GPL)
- */
-
-#ifndef _M68K_SERIAL_H
-#define _M68K_SERIAL_H
-
-
-/* m68k serial port types are numbered from 100 to avoid interference
- * with the PC types (1..4)
- */
-#define PORT_UNKNOWN	0
-#define PORT_8250	1
-#define PORT_16450	2
-#define PORT_16550	3
-#define PORT_16550A	4
-#define PORT_CIRRUS     5
-#define PORT_16650V2	7
-#define PORT_16750	8
-
-#define SER_SCC_NORM	100	/* standard SCC channel */
-#define	SER_SCC_DMA	101	/* SCC channel with DMA support */
-#define	SER_MFP_CTRL	102	/* standard MFP port with modem control signals */
-#define	SER_MFP_BARE	103	/* MFP port without modem controls */
-#define	SER_MIDI	104	/* Atari MIDI */
-#define	SER_AMIGA	105	/* Amiga built-in serial port */
-#define SER_IOEXT	106	/* Amiga GVP IO-Extender (16c552) */
-#define SER_MFC_III	107	/* Amiga BSC Multiface Card III (MC68681) */
-#define SER_WHIPPET	108	/* Amiga Hisoft Whippet PCMCIA (16c550B) */
-#define SER_SCC_MVME	109	/* MVME162/MVME172 ports */
-#define SER_SCC_MAC	110	/* Macintosh SCC channel */
-#define SER_HPDCA	111	/* HP DCA serial */
-#define SER_SCC_BVME	112	/* BVME6000 ports */
-
-struct serial_struct {
-	int	type;
-	int	line;
-	int	port;
-	int	irq;
-	int	flags;
-	int	xmit_fifo_size;
-	int	custom_divisor;
-	int	baud_base;
-	unsigned short	close_delay;
-	char	reserved_char[2];
-	int	hub6;
-	unsigned short	closing_wait; /* time to wait before closing */
-	unsigned short	closing_wait2; /* no longer used... */
-	int	reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ASYNC_CLOSING_WAIT_INF	0
-#define ASYNC_CLOSING_WAIT_NONE	65535
-
-/* This function tables does the abstraction from the underlying
- * hardware:
+ * currently this seems usefull only for a Q40,
+ * its an almost exact copy of ../asm/alpha/serial.h 
X  *
- *   init(): Initialize the port as necessary, set RTS and DTR and
- *      enable interrupts. It does not need to set the speed and other
- *      parameters, because change_speed() is called, too.
- *   deinit(): Stop and shutdown the port (e.g. disable interrupts, ...)
- *   enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt
- *      independently from other interrupt sources. If the int is
- *      enabled, the transmitter should also be restarted, i.e. if there
- *      are any chars to be sent, they should be put into the Tx
- *      register. The real en/disabling of the interrupt may be a no-op
- *      if there is no way to do this or it is too complex. This Tx ints
- *      are just disabled to save some interrupts if the transmitter is
- *      stopped anyway. But the restarting must be implemented!
- *   check_custom_divisor(): Check the given custom divisor for legality
- *      and return 0 if OK, non-zero otherwise.
- *   change_speed(): Set port speed, character size, number of stop
- *      bits and parity from the termios structure. If the user wants
- *      to set the speed with a custom divisor, he is required to
- *      check the baud_base first!
- *   throttle(): Set or clear the RTS line according to 'status'.
- *   set_break(): Set or clear the 'Send a Break' flag.
- *   get_serial_info(): Fill in the baud_base and custom_divisor
- *      fields of a serial_struct. It may also modify other fields, if
- *      needed.
- *   get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS.
- *   set_modem_info(): Set the status of RTS and DTR according to
- *      'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change
- *   ioctl(): Process any port-specific ioctl's. This pointer may be
- *      NULL, if the port has no own ioctl's.
- *   stop_receive(): Turn off the Rx part of the port, so no more characters
- *      will be received. This is called before shutting the port down.
- *   trans_empty(): Return !=0 if there are no more characters still to be
- *      sent out (Tx buffer register and FIFOs empty)
- *   check_open(): Is called before the port is opened. The driver can check
- *      if that's ok and return an error code, or keep track of the opening
- *      even before init() is called. Use deinit() for matching closing of the
- *      port.
- *
- */
-
-struct m68k_async_struct;
-
-typedef struct {
-	void (*init)( struct m68k_async_struct *info );
-	void (*deinit)( struct m68k_async_struct *info, int leave_dtr );
-	void (*enab_tx_int)( struct m68k_async_struct *info, int enab_flag );
-	int  (*check_custom_divisor)( struct m68k_async_struct *info, int baud_base,
-				     int divisor );
-	void (*change_speed)( struct m68k_async_struct *info );
-	void (*throttle)( struct m68k_async_struct *info, int status );
-	void (*set_break)( struct m68k_async_struct *info, int break_flag );
-	void (*get_serial_info)( struct m68k_async_struct *info,
-				struct serial_struct *retinfo );
-	unsigned int (*get_modem_info)( struct m68k_async_struct *info );
-	int  (*set_modem_info)( struct m68k_async_struct *info, int new_dtr,
-			       int new_rts );
-	int  (*ioctl)( struct tty_struct *tty, struct file *file,
-		      struct m68k_async_struct *info, unsigned int cmd,
-		      unsigned long arg );
-	void (*stop_receive)( struct m68k_async_struct *info );
-	int  (*trans_empty)( struct m68k_async_struct *info );
-	int  (*check_open)( struct m68k_async_struct *info, struct tty_struct *tty,
-			   struct file *file );
-} SERIALSWITCH;
-
-/*
- * Definitions for m68k_async_struct (and serial_struct) flags field
X  */
-#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-				   on the callout port */
-#define ASYNC_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
-#define ASYNC_SAK	0x0004	/* Secure Attention Key (Orange book) */
-#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ASYNC_SPD_MASK	0x1030
-#define ASYNC_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
-
-#define ASYNC_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
-#define ASYNC_SPD_CUST	0x0030  /* Use user-specified divisor */
-
-#define ASYNC_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
-#define ASYNC_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ASYNC_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define ASYNC_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define ASYNC_HARDPPS_CD	0x0800	/* Call hardpps when CD goes high  */
-
-#define ASYNC_SPD_SHI	0x1000	/* Use 230400 instead of 38400 bps */
-#define ASYNC_SPD_WARP	0x1010	/* Use 460800 instead of 38400 bps */
-
-#define ASYNC_FLAGS	0x1FFF	/* Possible legal async flags */
-#define ASYNC_USR_MASK 0x1430	/* Legal flags that non-privileged
-				 * users can set or reset */
-
-/* Internal flags used only by drivers/char/m68kserial.c */
-#define ASYNC_INITIALIZED	0x80000000 /* Serial port was initialized */
-#define ASYNC_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
-#define ASYNC_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
-#define ASYNC_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
-#define ASYNC_CLOSING		0x08000000 /* Serial port is closing */
-#define ASYNC_CTS_FLOW		0x04000000 /* Do CTS flow control */
-#define ASYNC_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-
-#define ASYNC_INTERNAL_FLAGS	0xFF000000 /* Internal flags */
-
-/*
- * Serial input interrupt line counters -- external structure
- * Four lines can interrupt: CTS, DSR, RI, DCD
- */
-struct serial_icounter_struct {
-	int cts, dsr, rng, dcd;
-	int rx, tx;
-	int frame, overrun, parity, brk;
-	int buf_overrun;
-	int reserved[9];
-};
X 
+#include <linux/config.h>
+#if 0
+#define rs_init serial_rs_init
+#define register_serial serial_register_serial
+#define unregister_serial serial_unregister_serial
+#endif
X 
-#ifdef __KERNEL__
X /*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
+ * This assumes you have a 1.8432 MHz clock for your UART.
X  *
- * For definitions of the flags field, see tty.h
- */
-
-#include <linux/termios.h>
-#include <linux/tqueue.h>
-
-#include <linux/config.h>	/* for Mac SCC extensions */
-
-#ifdef CONFIG_MAC
-#define NUM_ZSREGS    16
-struct mac_zschannel {
-	volatile unsigned char *control;
-	volatile unsigned char *data;
-};
-struct m68k_async_private;
-#endif
-
-struct m68k_async_struct {
-	int			magic;
-	int			baud_base;
-	int			port;
-	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			hub6;		/* HUB6 plus one */
-	int			type;
-	struct tty_struct 	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			timeout;
-	int			xmit_fifo_size;
-	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	int			IER; 	/* Interrupt Enable Register */
-	int			MCR; 	/* Modem control register */
-	int			MCR_noint; /* MCR with interrupts off */
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	struct tq_struct	tqueue;
-	struct termios		normal_termios;
-	struct termios		callout_termios;
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-	struct wait_queue	*delta_msr_wait;
-	struct async_icount	icount;	/* kernel counters for the 4 input interrupts */
-	struct m68k_async_struct	*next_port; /* For the linked list */
-	struct m68k_async_struct	*prev_port;
-	void			*board_base; /* board-base address for use with
-						boards carrying several UART's,
-						like some Amiga boards. */
-	unsigned short		nr_uarts;    /* UART-counter, that indicates
-						how many UART's there are on
-						the board.  If the board has a
-						IRQ-register, this can be used
-						to check if any of the uarts,
-						on the board has requested an
-						interrupt, instead of checking
-						IRQ-registers on all UART's */
-	SERIALSWITCH		*sw;		/* functions to manage this port */
-#ifdef CONFIG_MAC
-	struct m68k_async_private	*private;
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD ( 1843200 / 16 )
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
X #endif
-};
-
-#ifdef CONFIG_MAC
-struct m68k_async_private {
-	struct m68k_async_info	*zs_next;	/* For IRQ servicing chain */
-	struct mac_zschannel	*zs_channel;	/* Channel registers */
-	struct mac_zschannel	*zs_chan_a;	/* A side registers */
-	unsigned char		read_reg_zero;
-
-	char			soft_carrier;	/* Use soft carrier on this */
-	char			break_abort;	/* console, process brk/abrt */
-	char			kgdb_channel;	/* Kgdb running on this channel */
-	char			is_cons;	/* Is this our console. */
-	unsigned char		tx_active;	/* character being xmitted */
-	unsigned char		tx_stopped;	/* output is suspended */
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
-	 */
-	unsigned char		clk_divisor;	/* May be 1, 16, 32, or 64 */
-	int			zs_baud;
-
-	/* Current write register values */
-	unsigned char		curregs[NUM_ZSREGS];
-
-	/* Values we need to set next opportunity */
-	unsigned char		pendregs[NUM_ZSREGS];
-
-	char			change_needed;
-};
-#endif
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* Export to allow PCMCIA to use this - Dave Hinds */
-extern int register_serial(struct serial_struct *req);
-extern void unregister_serial(int line);
-extern struct m68k_async_struct rs_table[];
-extern task_queue tq_serial;
-
X 
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static __inline__ void rs_sched_event(struct m68k_async_struct *info, int event)
-{
-	info->event |= 1 << event;
-	queue_task(&info->tqueue, &tq_serial);
-	mark_bh(SERIAL_BH);
-}
-
-static __inline__ void rs_receive_char( struct m68k_async_struct *info,
-					    int ch, int err )
-{
-	struct tty_struct *tty = info->tty;
-	
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-		return;
-	tty->flip.count++;
-	switch(err) {
-	case TTY_BREAK:
-		info->icount.brk++;
-		if (info->flags & ASYNC_SAK)
-			do_SAK(tty);
-		break;
-	case TTY_PARITY:
-		info->icount.parity++;
-		break;
-	case TTY_OVERRUN:
-		info->icount.overrun++;
-		break;
-	case TTY_FRAME:
-		info->icount.frame++;
-		break;
-	}
-	*tty->flip.flag_buf_ptr++ = err;
-	*tty->flip.char_buf_ptr++ = ch;
-	info->icount.rx++;
-	tty_flip_buffer_push(tty);
-}
-
-static __inline__ int rs_get_tx_char( struct m68k_async_struct *info )
-{
-	unsigned char ch;
-	
-	if (info->x_char) {
-		ch = info->x_char;
-		info->icount.tx++;
-		info->x_char = 0;
-		return( ch );
-	}
-
-	if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped)
-		return( -1 );
-
-	ch = info->xmit_buf[info->xmit_tail++];
-	info->xmit_tail &= SERIAL_XMIT_SIZE - 1;
-	info->icount.tx++;
-	if (--info->xmit_cnt < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-	return( ch );
-}
-
-static __inline__ int rs_no_more_tx( struct m68k_async_struct *info )
-{
-	return( info->xmit_cnt <= 0 ||
-			info->tty->stopped ||
-			info->tty->hw_stopped );
-}
-
-static __inline__ void rs_dcd_changed( struct m68k_async_struct *info, int dcd )
-
-{
-	/* update input line counter */
-	info->icount.dcd++;
-	wake_up_interruptible(&info->delta_msr_wait);
-
-	if (info->flags & ASYNC_CHECK_CD) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
-		printk("ttyS%d CD now %s...", info->line,
-		       dcd ? "on" : "off");
-#endif		
-		if (dcd) {
-			wake_up_interruptible(&info->open_wait);
-		} else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			     (info->flags & ASYNC_CALLOUT_NOHUP))) {
-#ifdef SERIAL_DEBUG_OPEN
-			printk("scheduling hangup...");
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
X #endif
-			if (info->tty)
-				tty_hangup(info->tty);
-		}
-	}
-}
-
-
-void rs_stop( struct tty_struct *tty );
-void rs_start( struct tty_struct *tty );
-
-static __inline__ void rs_check_cts( struct m68k_async_struct *info, int cts )
-{
-	/* update input line counter */
-	info->icount.cts++;
-	wake_up_interruptible(&info->delta_msr_wait);
X 	
-	if ((info->flags & ASYNC_CTS_FLOW) && info->tty) {
-		if (info->tty->hw_stopped) {
-			if (cts) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
-				printk("CTS tx start...");
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS			\
+	{ 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, 	/* ttyS4 */	\
+	{ 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },	/* ttyS5 */	\
+	{ 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },	/* ttyS6 */	\
+	{ 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },	/* ttyS7 */	\
+	{ 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },	/* ttyS8 */	\
+	{ 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },	/* ttyS9 */	\
+	{ 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },	/* ttyS10 */	\
+	{ 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },	/* ttyS11 */	\
+	{ 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },	/* ttyS12 */	\
+	{ 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },	/* ttyS13 */	\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS14 (spare) */		\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS15 (spare) */		\
+	{ 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },	/* ttyS16 */	\
+	{ 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },	/* ttyS17 */	\
+	{ 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },	/* ttyS18 */	\
+	{ 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },	/* ttyS19 */	\
+	{ 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },	/* ttyS20 */	\
+	{ 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },	/* ttyS21 */	\
+	{ 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },	/* ttyS22 */	\
+	{ 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },	/* ttyS23 */	\
+	{ 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },	/* ttyS24 */	\
+	{ 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },	/* ttyS25 */	\
+	{ 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },	/* ttyS26 */	\
+	{ 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },	/* ttyS27 */	\
+	{ 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },	/* ttyS28 */	\
+	{ 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },	/* ttyS29 */	\
+	{ 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },	/* ttyS30 */	\
+	{ 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },	/* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
X #endif
-				info->tty->hw_stopped = 0;
-				rs_start( info->tty );
-				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-				return;
-			}
-		} else {
-			if (!cts) {
-				info->tty->hw_stopped = 1;
-				rs_stop( info->tty );
-			}
-		}
-	}
-}
-
-
-#endif /* __KERNEL__ */
X 
-#endif /* _M68K_SERIAL_H */
+#define SERIAL_PORT_DFNS		\
+	STD_SERIAL_PORT_DEFNS		\
+	EXTRA_SERIAL_PORT_DEFNS
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h
--- v2.2.7/linux/include/asm-m68k/setup.h	Wed Jan 20 23:14:06 1999
+++ linux/include/asm-m68k/setup.h	Tue May 11 09:57:14 1999
@@ -39,6 +39,8 @@
X #define MACH_MVME16x  7
X #define MACH_BVME6000 8
X #define MACH_HP300    9
+#define MACH_Q40     10
+#define MACH_SUN3X   11
X 
X #ifdef __KERNEL__
X 
@@ -49,7 +51,9 @@
X #if !defined(CONFIG_AMIGA)
X #  define MACH_IS_AMIGA (0)
X #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
X #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
X #else
X #  define MACH_AMIGA_ONLY
@@ -60,7 +64,9 @@
X #if !defined(CONFIG_ATARI)
X #  define MACH_IS_ATARI (0)
X #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                      \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
X #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
X #else
X #  define MACH_ATARI_ONLY
@@ -71,7 +77,9 @@
X #if !defined(CONFIG_MAC)
X #  define MACH_IS_MAC (0)
X #elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
-	|| defined(CONFIG_HP300) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)                 \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                        \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
X #  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
X #else
X #  define MACH_MAC_ONLY
@@ -88,7 +96,9 @@
X #if !defined (CONFIG_APOLLO)
X #  define MACH_IS_APOLLO (0)
X #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)              \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
X #  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
X #else
X #  define MACH_APOLLO_ONLY
@@ -96,10 +106,25 @@
X #  define MACH_TYPE (MACH_APOLLO)
X #endif
X 
+#if !defined (CONFIG_MVME147)
+#  define MACH_IS_MVME147 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x)
+#  define MACH_IS_MVME147 (m68k_machtype == MACH_MVME147)
+#else
+#  define MACH_MVME147_ONLY
+#  define MACH_IS_MVME147 (1)
+#  define MACH_TYPE (MACH_MVME147)
+#endif
+
X #if !defined (CONFIG_MVME16x)
X #  define MACH_IS_MVME16x (0)
X #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) || defined(CONFIG_HP300)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)               \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
X #  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
X #else
X #  define MACH_MVME16x_ONLY
@@ -110,7 +135,9 @@
X #if !defined (CONFIG_BVME6000)
X #  define MACH_IS_BVME6000 (0)
X #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_HP300)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_HP300) || defined(CONFIG_Q40)                     \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
X #  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
X #else
X #  define MACH_BVME6000_ONLY
@@ -121,12 +148,40 @@
X #if !defined (CONFIG_HP300)
X #  define MACH_IS_HP300 (0)
X #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
-	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
-#  define MAC_IS_HP300 (m68k_machtype == MACH_HP300)
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_Q40) \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+#  define MACH_IS_HP300 (m68k_machtype == MACH_HP300)
X #else
X #  define MACH_HP300_ONLY
X #  define MACH_IS_HP300 (1)
X #  define MACH_TYPE (MACH_HP300)
+#endif
+
+#if !defined (CONFIG_Q40)
+#  define MACH_IS_Q40 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+	|| defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+#  define MACH_IS_Q40 (m68k_machtype == MACH_Q40)
+#else
+#  define MACH_Q40_ONLY
+#  define MACH_IS_Q40 (1)
+#  define MACH_TYPE (MACH_Q40)
+#endif
+
+#if !defined (CONFIG_SUN3X)
+#  define MACH_IS_SUN3X (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)                \
+	|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300)                \
+	|| defined(CONFIG_Q40) || defined(CONFIG_MVME147)
+#  define MACH_IS_SUN3X (m68k_machtype == MACH_SUN3X)
+#else
+#  define CONFIG_SUN3X_ONLY
+#  define MACH_IS_SUN3X (1)
+#  define MACH_TYPE (MACH_SUN3X)
X #endif
X 
X #ifndef MACH_TYPE
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/sun3x.h linux/include/asm-m68k/sun3x.h
--- v2.2.7/linux/include/asm-m68k/sun3x.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3x.h	Tue May 11 09:57:14 1999
@@ -0,0 +1,24 @@
+#ifndef SUN3X_H
+#define SUN3X_H
+
+/* hardware addresses */
+#define SUN3X_IOMMU       0x60000000
+#define SUN3X_ENAREG      0x61000000
+#define SUN3X_INTREG      0x61001400
+#define SUN3X_DIAGREG     0x61001800
+#define SUN3X_ZS1         0x62000000
+#define SUN3X_ZS2         0x62002000
+#define SUN3X_LANCE       0x65002000
+#define SUN3X_EEPROM      0x64000000
+#define SUN3X_IDPROM      0x640007d8
+#define SUN3X_VIDEO_BASE  0x50000000
+#define SUN3X_VIDEO_P4ID  0x50300000
+#define SUN3X_ESP_BASE	  0x66000000
+#define SUN3X_ESP_DMA	  0x66001000
+
+/* some NVRAM addresses */
+#define SUN3X_EEPROM_CONS 	(SUN3X_EEPROM + 0x1f)
+#define SUN3X_EEPROM_PORTA	(SUN3X_EEPROM + 0x58)
+#define SUN3X_EEPROM_PORTB	(SUN3X_EEPROM + 0x60)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v2.2.7/linux/include/asm-m68k/system.h	Wed Jan 20 23:14:06 1999
+++ linux/include/asm-m68k/system.h	Tue May 11 09:57:14 1999
@@ -43,12 +43,14 @@
X  * the mm structures are shared in d2 (to avoid atc flushing).
X  */
X asmlinkage void resume(void);
-#define switch_to(prev,next) { \
+#define switch_to(prev,next,last) { \
X   register void *_prev __asm__ ("a0") = (prev); \
X   register void *_next __asm__ ("a1") = (next); \
+  register void *_last __asm__ ("d1"); \
X   __asm__ __volatile__("jbsr " SYMBOL_NAME_STR(resume) \
-		       : : "a" (_prev), "a" (_next) \
+		       : "=d" (_last) : "a" (_prev), "a" (_next) \
X 		       : "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \
+  (last) = _last; \
X }
X 
X #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
@@ -66,6 +68,8 @@
X #define __cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
X #define nop() __asm__ __volatile__ ("nop"::)
X #define mb()  __asm__ __volatile__ (""   : : :"memory")
+#define rmb()  __asm__ __volatile__ (""   : : :"memory")
+#define wmb()  __asm__ __volatile__ (""   : : :"memory")
X 
X #define __save_flags(x) \
X __asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
diff -u --recursive --new-file v2.2.7/linux/include/asm-m68k/uaccess.h linux/include/asm-m68k/uaccess.h
--- v2.2.7/linux/include/asm-m68k/uaccess.h	Thu Jan  7 15:11:40 1999
+++ linux/include/asm-m68k/uaccess.h	Tue May 11 09:57:14 1999
@@ -759,6 +759,10 @@
X #define __copy_from_user(to, from, n) copy_from_user(to, from, n)
X #define __copy_to_user(to, from, n) copy_to_user(to, from, n)
X 
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+
X /*
X  * Copy a null terminated string from userspace.
X  */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/adb.h linux/include/asm-ppc/adb.h
--- v2.2.7/linux/include/asm-ppc/adb.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/adb.h	Thu Apr 29 12:39:01 1999
@@ -21,6 +21,16 @@
X #define ADB_RET_OK	0
X #define ADB_RET_TIMEOUT	3
X 
+/* The kind of ADB request. The controller may emulate some
+   of all of those CUDA/PMU packet kinds */
+#define ADB_PACKET	0
+#define CUDA_PACKET	1
+#define ERROR_PACKET	2
+#define TIMER_PACKET	3
+#define POWER_PACKET	4
+#define MACIIC_PACKET	5
+#define PMU_PACKET	6
+
X #ifdef __KERNEL__
X 
X struct adb_request {
@@ -41,19 +51,37 @@
X     unsigned char id[16];
X };
X 
-extern enum adb_hw {
-	ADB_NONE, ADB_VIACUDA, ADB_VIAPMU, ADB_MACIO
-} adb_hardware;
-
-extern int (*adb_send_request)(struct adb_request *req, int sync);
-extern int (*adb_autopoll)(int devs);
-extern int (*adb_reset_bus)(void);
+/* Messages sent thru the client_list notifier. You should NOT stop
+   the operation, at least not with this version */
+enum adb_message {
+    ADB_MSG_POWERDOWN,	/* Currently called before sleep only */
+    ADB_MSG_PRE_RESET,	/* Called before resetting the bus */
+    ADB_MSG_POST_RESET	/* Called after resetting the bus (re-do init & register) */
+};
+extern struct notifier_block *adb_client_list;
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 30'
echo 'File patch-2.2.8 is continued in part 31'
echo 31 > _shar_seq_.tmp
#!/bin/sh
# this is part 31 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 31; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
+
+/* Kind of ADB controller */
+enum adb_hw {
+    ADB_NONE, ADB_VIACUDA, ADB_VIAPMU, ADB_MACIO, ADB_UNKNOWN
+};
+
+/* Definition of a controller */
+extern struct adb_controller {
+    enum adb_hw		kind;
+	
+    int		(*send_request)(struct adb_request *req, int sync);
+    int		(*autopoll)(int devs);
+    int		(*reset_bus)(void);
+    void	(*poll)(void);
+} *adb_controller;
+extern enum adb_hw adb_hardware;
X 
X /* Values for adb_request flags */
X #define ADBREQ_REPLY	1	/* expect reply */
X #define ADBREQ_SYNC	2	/* poll until done */
X 
X void adb_init(void);
+
X int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
X 		int flags, int nbytes, ...);
X int adb_register(int default_id,int handler_id,struct adb_ids *ids,
@@ -62,6 +90,10 @@
X 
X int adb_try_handler_change(int address, int new_id);
X int adb_get_infos(int address, int *original_address, int *handler_id);
+
+int adb_reset_bus(void);
+
+void adb_poll(void);
X 
X #endif /* __KERNEL__ */
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/cuda.h linux/include/asm-ppc/cuda.h
--- v2.2.7/linux/include/asm-ppc/cuda.h	Fri May  8 23:14:56 1998
+++ linux/include/asm-ppc/cuda.h	Thu Apr 29 12:39:01 1999
@@ -5,15 +5,6 @@
X  * Copyright (C) 1996 Paul Mackerras.
X  */
X 
-/* First byte sent to or received from CUDA */
-#define ADB_PACKET	0
-#define CUDA_PACKET	1
-#define ERROR_PACKET	2
-#define TIMER_PACKET	3
-#define POWER_PACKET	4
-#define MACIIC_PACKET	5
-#define PMU_PACKET	6
-
X /* CUDA commands (2nd byte) */
X #define CUDA_WARM_START		0
X #define CUDA_AUTOPOLL		1
@@ -41,7 +32,7 @@
X void via_cuda_init(void);
X int cuda_request(struct adb_request *req,
X 		 void (*done)(struct adb_request *), int nbytes, ...);
-int cuda_send_request(struct adb_request *req);
X void cuda_poll(void);
+int cuda_present(void);
X 
X #endif	/* __KERNEL */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.2.7/linux/include/asm-ppc/dma.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/dma.h	Thu Apr 29 12:39:01 1999
@@ -35,36 +35,9 @@
X /* Doesn't really apply... */
X #define MAX_DMA_ADDRESS      0xFFFFFFFF
X 
-#if defined(CONFIG_MACH_SPECIFIC)
-
-#if defined(CONFIG_PREP)
-#define DMA_MODE_READ 0x44
-#define DMA_MODE_WRITE 0x48
-#define ISA_DMA_THRESHOLD 0x00ffffff
-#endif /* CONFIG_PREP */
-
-#if defined(CONFIG_CHRP)
-#define DMA_MODE_READ 0x44
-#define DMA_MODE_WRITE 0x48
-#define ISA_DMA_THRESHOLD ~0L
-#endif /* CONFIG_CHRP */
-
-#ifdef CONFIG_PMAC
-#define DMA_MODE_READ 1
-#define DMA_MODE_WRITE 2
-#define ISA_DMA_THRESHOLD ~0L
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_APUS
-/* This is bogus and should go away. */
-#define ISA_DMA_THRESHOLD (0x00ffffff)
-#endif
-
-#else
X /* in arch/ppc/kernel/setup.c -- Cort */
X extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
X extern unsigned long ISA_DMA_THRESHOLD;
-#endif
X 
X 
X #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
@@ -204,7 +177,7 @@
X #define DMA2_EXT_REG               0x4D6
X 
X #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
-#define DMA_AUTOINIT	0x10
+#define DMA_AUTOINIT   	 0x10
X 
X extern spinlock_t  dma_spin_lock;
X 
@@ -427,9 +400,8 @@
X extern void free_dma(unsigned int dmanr);	/* release it again */
X 
X #ifdef CONFIG_PCI_QUIRKS
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy    (0)
+extern int isa_dma_bridge_buggy;                                        
+#else                                                         
+#define isa_dma_bridge_buggy   (0)
X #endif
-
X #endif /* _ASM_DMA_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.2.7/linux/include/asm-ppc/hardirq.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/hardirq.h	Thu Apr 29 12:39:01 1999
@@ -1,22 +1,22 @@
X #ifndef __ASM_HARDIRQ_H
X #define __ASM_HARDIRQ_H
X 
-extern unsigned int local_irq_count[NR_CPUS];
+extern unsigned int ppc_local_irq_count[NR_CPUS];
X 
X /*
X  * Are we in an interrupt context? Either doing bottom half
X  * or hardware interrupt processing?
X  */
X #define in_interrupt() ({ int __cpu = smp_processor_id(); \
-	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+	(ppc_local_irq_count[__cpu] + ppc_local_bh_count[__cpu] != 0); })
X 
X #ifndef __SMP__
X 
-#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)	(ppc_local_irq_count[cpu] == 0)
X #define hardirq_endlock(cpu)	do { } while (0)
X 
-#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+#define hardirq_enter(cpu)	(ppc_local_irq_count[cpu]++)
+#define hardirq_exit(cpu)	(ppc_local_irq_count[cpu]--)
X 
X #define synchronize_irq()	do { } while (0)
X 
@@ -39,14 +39,14 @@
X 
X static inline void hardirq_enter(int cpu)
X {
-	++local_irq_count[cpu];
+	++ppc_local_irq_count[cpu];
X 	atomic_inc(&global_irq_count);
X }
X 
X static inline void hardirq_exit(int cpu)
X {
X 	atomic_dec(&global_irq_count);
-	--local_irq_count[cpu];
+	--ppc_local_irq_count[cpu];
X }
X 
X static inline int hardirq_trylock(int cpu)
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.2.7/linux/include/asm-ppc/ide.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/ide.h	Thu May  6 23:14:37 1999
@@ -11,17 +11,8 @@
X #ifndef __ASMPPC_IDE_H
X #define __ASMPPC_IDE_H
X 
-#include <linux/config.h>
-/*
- * On APUS, nearly everything comes from the m68k file
- * -- Cort
- */
-#ifdef CONFIG_APUS
-#include <linux/hdreg.h>
-#define ide_init_hwif_ports m68k_ide_init_hwif_ports 
-#include <asm-m68k/ide.h>
-#undef ide_init_hwif_ports
-#endif /* CONFIG_APUS */
+#include <linux/sched.h>
+#include <asm/processor.h>
X 
X #ifndef MAX_HWIFS
X #define MAX_HWIFS	4
@@ -29,6 +20,12 @@
X 
X typedef unsigned int ide_ioreg_t;
X 
+#ifdef __KERNEL__
+
+#include <linux/hdreg.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
X extern int pmac_ide_ports_known;
X extern ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
X extern int pmac_ide_irq[MAX_HWIFS];
@@ -40,43 +37,42 @@
X extern unsigned int chrp_ide_irq;
X extern void chrp_ide_probe(void);
X 
+struct ide_machdep_calls {
+        void        (*insw)(ide_ioreg_t port, void *buf, int ns);
+        void        (*outsw)(ide_ioreg_t port, void *buf, int ns);
+        int         (*default_irq)(ide_ioreg_t base);
+        ide_ioreg_t (*default_io_base)(int index);
+        int         (*check_region)(ide_ioreg_t from, unsigned int extent);
+        void        (*request_region)(ide_ioreg_t from,
+                                      unsigned int extent,
+                                      const char *name);
+        void        (*release_region)(ide_ioreg_t from,
+                                      unsigned int extent);
+        void        (*fix_driveid)(struct hd_driveid *id);
+        void        (*ide_init_hwif)(ide_ioreg_t *p,
+                                     ide_ioreg_t base,
+                                     int *irq); 
+
+        int io_base;
+};
+
+extern struct ide_machdep_calls ppc_ide_md;
+
X void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void prep_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void chrp_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
X void ide_insw(ide_ioreg_t port, void *buf, int ns);
X void ide_outsw(ide_ioreg_t port, void *buf, int ns);
+void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
X 
X #undef insw
X #define insw(port, buf, ns) 	do {				\
-	if ( _machine & (_MACH_chrp|_MACH_mbx) )		\
-		 ide_insw((port)+_IO_BASE, (buf), (ns));  	\
-	else if ( _machine & (_MACH_Pmac|_MACH_apus) )		\
-		 ide_insw((port), (buf), (ns));  		\
-	else							\
-		/* this must be the same as insw in io.h!! */	\
-		_insw((unsigned short *)((port)+_IO_BASE), (buf), (ns)); \
+	ppc_ide_md.insw((port), (buf), (ns));			\
X } while (0)
X      
X #undef outsw
X #define outsw(port, buf, ns) 	do {				\
-	if ( _machine & (_MACH_chrp|_MACH_mbx) ) 		\
-		ide_outsw((port)+_IO_BASE, (buf), (ns)); 	\
-	else if ( _machine & (_MACH_Pmac|_MACH_apus) )		\
-		ide_outsw((port), (buf), (ns)); 		\
-	else							\
-		/* this must be the same as outsw in io.h!! */	\
-		_outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns)); \
+	ppc_ide_md.outsw((port), (buf), (ns));			\
X } while (0)
X 
-#ifndef CONFIG_APUS
-#ifdef __KERNEL__
-
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
X #undef	SUPPORT_SLOW_DATA_PORTS
X #define	SUPPORT_SLOW_DATA_PORTS	0
X #undef	SUPPORT_VLB_SYNC
@@ -86,192 +82,41 @@
X 
X static __inline__ int ide_default_irq(ide_ioreg_t base)
X {
-	if ( _machine == _MACH_Pmac )
-		return 0;
-	else if ( _machine == _MACH_mbx )
-		/* IRQ 14 when in legacy mode on MBX */
-		return 14;
-        else if ( _machine == _MACH_chrp) {
-                if (chrp_ide_ports_known == 0) 
-			chrp_ide_probe();
-                return chrp_ide_irq;
-        }
-	switch (base) {
-		case 0x1f0: return 13;
-		case 0x170: return 13;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		default:
-			return 0;
-	}
+	return ppc_ide_md.default_irq(base);
X }
X 
X static __inline__ ide_ioreg_t ide_default_io_base(int index)
X {
-#if defined(CONFIG_BLK_DEV_IDE_PMAC)
-        if (_machine == _MACH_Pmac) {
-		return pmac_ide_regbase[index];
-	}
-#endif	
-	if (_machine == _MACH_mbx) return index;
-        if ( _machine == _MACH_chrp ) {
-                if (chrp_ide_ports_known == 0)
-                        chrp_ide_probe();
-                return chrp_ide_regbase[index];
-        }
-	switch (index) {
-		case 0:	return 0x1f0;
-		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		default:
-			return 0;
-	}
+	return ppc_ide_md.default_io_base(index);
X }
X 
X static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
X {
-	if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx))
-		return 0;
-	return check_region(from, extent);
+	return ppc_ide_md.check_region(from, extent);
X }
X 
X static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
X {
-	if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
-		return;
-	request_region(from, extent, name);
+	ppc_ide_md.request_region(from, extent, name);
X }
X 
X static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
X {
-	if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
-		return;
-	release_region(from, extent);
+	ppc_ide_md.release_region(from, extent);
X }
X 
-/* Convert the shorts/longs in hd_driveid from little to big endian;
-   chars are endian independent, of course, but strings need to be flipped.
-   (Despite what it says in drivers/block/ide.h, they come up as little endian...)
-   Changes to linux/hdreg.h may require changes here. */
X static __inline__ void ide_fix_driveid (struct hd_driveid *id) {
-  if ( _machine & (_MACH_chrp|_MACH_mbx|_MACH_Pmac) ) { 	\
-		int i;
-		unsigned short *stringcast;
-		id->config         = __le16_to_cpu(id->config);
-		id->cyls           = __le16_to_cpu(id->cyls);
-		id->reserved2      = __le16_to_cpu(id->reserved2);
-		id->heads          = __le16_to_cpu(id->heads);
-		id->track_bytes    = __le16_to_cpu(id->track_bytes);
-		id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-		id->sectors        = __le16_to_cpu(id->sectors);
-		id->vendor0        = __le16_to_cpu(id->vendor0);
-		id->vendor1        = __le16_to_cpu(id->vendor1);
-		id->vendor2        = __le16_to_cpu(id->vendor2);
-		stringcast = (unsigned short *)&id->serial_no[0];
-		for (i=0; i<(20/2); i++)
-			stringcast[i] = __le16_to_cpu(stringcast[i]);
-		id->buf_type       = __le16_to_cpu(id->buf_type);
-		id->buf_size       = __le16_to_cpu(id->buf_size);
-		id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-		stringcast = (unsigned short *)&id->fw_rev[0];
-		for (i=0; i<(8/2); i++)
-			stringcast[i] = __le16_to_cpu(stringcast[i]);
-		stringcast = (unsigned short *)&id->model[0];
-		for (i=0; i<(40/2); i++)
-			stringcast[i] = __le16_to_cpu(stringcast[i]);
-		id->dword_io       = __le16_to_cpu(id->dword_io);
-		id->reserved50     = __le16_to_cpu(id->reserved50);
-		id->field_valid    = __le16_to_cpu(id->field_valid);
-		id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-		id->cur_heads      = __le16_to_cpu(id->cur_heads);
-		id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-		id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-		id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-		id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-		id->dma_1word      = __le16_to_cpu(id->dma_1word);
-		id->dma_mword      = __le16_to_cpu(id->dma_mword);
-		id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-		id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-		id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-		id->eide_pio       = __le16_to_cpu(id->eide_pio);
-		id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-		id->word69         = __le16_to_cpu(id->word69);
-		id->word70         = __le16_to_cpu(id->word70);
-		id->word71         = __le16_to_cpu(id->word71);
-		id->word72         = __le16_to_cpu(id->word72);
-		id->word73         = __le16_to_cpu(id->word73);
-		id->word74         = __le16_to_cpu(id->word74);
-		id->word75         = __le16_to_cpu(id->word75);
-		id->word76         = __le16_to_cpu(id->word76);
-		id->word77         = __le16_to_cpu(id->word77);
-		id->word78         = __le16_to_cpu(id->word78);
-		id->word79         = __le16_to_cpu(id->word79);
-		id->word80         = __le16_to_cpu(id->word80);
-		id->word81         = __le16_to_cpu(id->word81);
-		id->command_sets   = __le16_to_cpu(id->command_sets);
-		id->word83         = __le16_to_cpu(id->word83);
-		id->word84         = __le16_to_cpu(id->word84);
-		id->word85         = __le16_to_cpu(id->word85);
-		id->word86         = __le16_to_cpu(id->word86);
-		id->word87         = __le16_to_cpu(id->word87);
-		id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-		id->word89         = __le16_to_cpu(id->word89);
-		id->word90         = __le16_to_cpu(id->word90);
-		id->word91         = __le16_to_cpu(id->word91);
-		id->word92         = __le16_to_cpu(id->word92);
-		id->word93         = __le16_to_cpu(id->word93);
-		id->word94         = __le16_to_cpu(id->word94);
-		id->word95         = __le16_to_cpu(id->word95);
-		id->word96         = __le16_to_cpu(id->word96);
-		id->word97         = __le16_to_cpu(id->word97);
-		id->word98         = __le16_to_cpu(id->word98);
-		id->word99         = __le16_to_cpu(id->word99);
-		id->word100        = __le16_to_cpu(id->word100);
-		id->word101        = __le16_to_cpu(id->word101);
-		id->word102        = __le16_to_cpu(id->word102);
-		id->word103        = __le16_to_cpu(id->word103);
-		id->word104        = __le16_to_cpu(id->word104);
-		id->word105        = __le16_to_cpu(id->word105);
-		id->word106        = __le16_to_cpu(id->word106);
-		id->word107        = __le16_to_cpu(id->word107);
-		id->word108        = __le16_to_cpu(id->word108);
-		id->word109        = __le16_to_cpu(id->word109);
-		id->word110        = __le16_to_cpu(id->word110);
-		id->word111        = __le16_to_cpu(id->word111);
-		id->word112        = __le16_to_cpu(id->word112);
-		id->word113        = __le16_to_cpu(id->word113);
-		id->word114        = __le16_to_cpu(id->word114);
-		id->word115        = __le16_to_cpu(id->word115);
-		id->word116        = __le16_to_cpu(id->word116);
-		id->word117        = __le16_to_cpu(id->word117);
-		id->word118        = __le16_to_cpu(id->word118);
-		id->word119        = __le16_to_cpu(id->word119);
-		id->word120        = __le16_to_cpu(id->word120);
-		id->word121        = __le16_to_cpu(id->word121);
-		id->word122        = __le16_to_cpu(id->word122);
-		id->word123        = __le16_to_cpu(id->word123);
-		id->word124        = __le16_to_cpu(id->word124);
-		id->word125        = __le16_to_cpu(id->word125);
-		id->word126        = __le16_to_cpu(id->word126);
-		id->word127        = __le16_to_cpu(id->word127);
-		id->security       = __le16_to_cpu(id->security);
-		for (i=0; i<127; i++)
-			id->reserved[i] = __le16_to_cpu(id->reserved[i]);
-	}
+        ppc_ide_md.fix_driveid(id);
X }
X 
X #undef inb
-#define inb(port)	\
-	in_8((unsigned char *)((port) + \
-			       ((_machine==_MACH_Pmac)? 0: _IO_BASE) ) )
+#define inb(port)	in_8((unsigned char *)((port) + ppc_ide_md.io_base))
X #undef inb_p
X #define inb_p(port)	inb(port)
X 
X #undef outb
X #define outb(val, port)	\
-	out_8((unsigned char *)((port) + \
-				((_machine==_MACH_Pmac)? 0: _IO_BASE) ), (val) )
+	out_8((unsigned char *)((port) + ppc_ide_md.io_base), (val) )
X #undef outb_p
X #define outb_p(val, port)	outb(val, port)
X 
@@ -305,6 +150,5 @@
X #define ide_get_lock(lock, hdlr, data)	do {} while (0)
X 
X #endif /* __KERNEL__ */
-#endif /* CONFIG_APUS */
X 
X #endif /* __ASMPPC_IDE_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.2.7/linux/include/asm-ppc/io.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/io.h	Thu Apr 29 12:39:01 1999
@@ -5,8 +5,6 @@
X #include <asm/page.h>
X #include <asm/byteorder.h>
X 
-#define KERNELBASE	0xc0000000
-
X #define SIO_CONFIG_RA	0x398
X #define SIO_CONFIG_RD	0x399
X 
@@ -18,7 +16,7 @@
X #define CHRP_ISA_MEM_BASE 	0xf7000000
X #define CHRP_PCI_DRAM_OFFSET 	0
X #define PREP_ISA_IO_BASE 	0x80000000
-#define PREP_ISA_MEM_BASE 	0xd0000000
+#define PREP_ISA_MEM_BASE 	0xc0000000
X #define PREP_PCI_DRAM_OFFSET 	0x80000000
X 
X #ifdef CONFIG_MBX
@@ -49,7 +47,7 @@
X #define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
X #else
X #define readw(addr) in_le16((volatile unsigned short *)(addr))
-#define readl(addr) in_le32((volatile unsigned *)addr)
+#define readl(addr) in_le32((volatile unsigned *)(addr))
X #define writew(b,addr) out_le16((volatile unsigned short *)(addr),(b))
X #define writel(b,addr) out_le32((volatile unsigned *)(addr),(b))
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.2.7/linux/include/asm-ppc/irq.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/irq.h	Thu Apr 29 12:39:01 1999
@@ -3,7 +3,7 @@
X #ifndef _ASM_IRQ_H
X #define _ASM_IRQ_H
X 
-#include <asm/processor.h>		/* for is_prep() */
+#include <asm/machdep.h>		/* ppc_md */
X 
X extern void disable_irq(unsigned int);
X extern void enable_irq(unsigned int);
@@ -42,7 +42,14 @@
X  */
X static __inline__ int irq_cannonicalize(int irq)
X {
-	return (((is_prep || is_chrp) && irq == 2) ? 9 : irq);
+	if (ppc_md.irq_cannonicalize)
+	{
+		return ppc_md.irq_cannonicalize(irq);
+	}
+	else
+	{
+		return irq;
+	}
X }
X #endif
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.2.7/linux/include/asm-ppc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-ppc/keyboard.h	Thu Apr 29 12:39:01 1999
@@ -17,7 +17,7 @@
X 
X #include <linux/config.h>
X #include <asm/adb.h>
-
+#include <asm/machdep.h>
X #ifdef CONFIG_APUS
X #include <asm-m68k/keyboard.h>
X #else
@@ -26,132 +26,44 @@
X #define DISABLE_KBD_DURING_INTERRUPTS	0
X #define INIT_KBD
X 
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern int mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-
X static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
X {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_setkeycode(scancode,keycode);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_setkeycode(scancode,keycode);
-#else
-		/* I'm not actually sure if it's legal to have a CHRP machine
-		 * without an ADB controller. In any case, this should really
-		 * be changed to be a test to see if an ADB _keyboard_ exists
-		 * (not just a controller), but that's another story for
-		 * another night.
-		 */
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_setkeycode(scancode,keycode);
-		else
-			return mackbd_setkeycode(scancode,keycode);
-#endif
-	else
-		return mackbd_setkeycode(scancode,keycode);
+	return ppc_md.kbd_setkeycode(scancode, keycode);
X }
-
-static inline int kbd_getkeycode(unsigned int x)
+  
+static inline int kbd_getkeycode(unsigned int scancode)
X {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_getkeycode(x);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_getkeycode(x);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_getkeycode(x);
-		else
-			return mackbd_getkeycode(x);
-#endif
-	else
-		return mackbd_getkeycode(x);
+	return ppc_md.kbd_getkeycode(scancode);
X }
-
+  
X static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode)
+				char raw_mode)
X {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_translate(keycode,keycodep,raw_mode);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_translate(keycode,keycodep,raw_mode);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_translate(keycode,keycodep,raw_mode);
-		else
-			return mackbd_translate(keycode,keycodep,raw_mode);
-#endif
-	else
-		return mackbd_translate(keycode,keycodep,raw_mode);
-	
+	return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
X }
-
+  
X static inline int kbd_unexpected_up(unsigned char keycode)
X {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_unexpected_up(keycode);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_unexpected_up(keycode);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_unexpected_up(keycode);
-		else
-			return mackbd_unexpected_up(keycode);
-#endif
-	else
-		return mackbd_unexpected_up(keycode);
-	
+	return ppc_md.kbd_unexpected_up(keycode);
X }
-
+  
X static inline void kbd_leds(unsigned char leds)
X {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		pckbd_leds(leds);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		pckbd_leds(leds);
-#else
-		if ( adb_hardware == ADB_NONE )
-			pckbd_leds(leds);
-		else
-			mackbd_leds(leds);
-#endif
-	else
-		mackbd_leds(leds);
+	ppc_md.kbd_leds(leds);
X }
-
+  
X static inline void kbd_init_hw(void)
X {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		pckbd_init_hw();
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		pckbd_init_hw();
+	ppc_md.kbd_init_hw();
+}
+
+#define kbd_sysrq_xlate	(ppc_md.kbd_sysrq_xlate)
+
+#ifdef CONFIG_MAC_KEYBOARD
+# define SYSRQ_KEY 0x69
X #else
-		if ( adb_hardware == ADB_NONE )
-			pckbd_init_hw();
-		else
-			mackbd_init_hw();
+# define SYSRQ_KEY 0x54
X #endif
-	else
-		mackbd_init_hw();
-}
X 
X #endif /* CONFIG_APUS */
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.2.7/linux/include/asm-ppc/machdep.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-ppc/machdep.h	Thu Apr 29 12:39:01 1999
@@ -1,3 +1,4 @@
+
X #ifndef _PPC_MACHDEP_H
X #define _PPC_MACHDEP_H
X 
@@ -7,6 +8,69 @@
X #include <asm-m68k/machdep.h>
X #endif
X 
-#endif /* _PPC_MACHDEP_H */
+struct pt_regs;
+
+struct machdep_calls {
+	void		(*setup_arch)(unsigned long * memory_start_p,
+				unsigned long * memory_end_p);
+	/* Optional, may be NULL. */
+	int		(*setup_residual)(char *buffer);
+	/* Optional, may be NULL. */
+	int		(*get_cpuinfo)(char *buffer);
+	/* Optional, may be NULL. */
+	unsigned int	(*irq_cannonicalize)(unsigned int irq);
+	void		(*init_IRQ)(void);
+	void		(*do_IRQ)(struct pt_regs *regs, int cpu, int isfake);
+
+	/* A general init function, called by ppc_init in init/main.c.
+	   May be NULL. */
+	void		(*init)(void);
+
+	void		(*restart)(char *cmd);
+	void		(*power_off)(void);
+	void		(*halt)(void);
+
+	void		(*time_init)(void); /* Optional, may be NULL */
+	int		(*set_rtc_time)(unsigned long nowtime);
+	unsigned long	(*get_rtc_time)(void);
+	void		(*calibrate_decr)(void);
X 
+	unsigned char 	(*nvram_read_val)(int addr);
+	void		(*nvram_write_val)(int addr, unsigned char val);
X 
+/* Tons of keyboard stuff. */
+	int		(*kbd_setkeycode)(unsigned int scancode,
+				unsigned int keycode);
+	int		(*kbd_getkeycode)(unsigned int scancode);
+	int		(*kbd_translate)(unsigned char scancode,
+				unsigned char *keycode,
+				char raw_mode);
+	char		(*kbd_unexpected_up)(unsigned char keycode);
+	void		(*kbd_leds)(unsigned char leds);
+	void		(*kbd_init_hw)(void);
+#ifdef CONFIG_MAGIC_SYSRQ
+	unsigned char 	*kbd_sysrq_xlate;
+#endif
+
+	/* PCI interfaces */
+	int (*pcibios_read_config_byte)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned char *val);
+	int (*pcibios_read_config_word)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned short *val);
+	int (*pcibios_read_config_dword)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned int *val);
+	int (*pcibios_write_config_byte)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned char val);
+	int (*pcibios_write_config_word)(unsigned char bus, 
+		unsigned char dev_fn, unsigned char offset, unsigned short val);
+	int (*pcibios_write_config_dword)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned int val);
+	void (*pcibios_fixup)(void);
+};
+
+extern struct machdep_calls ppc_md;
+extern char cmd_line[512];
+
+extern void setup_pci_ptrs(void);
+
+#endif /* _PPC_MACHDEP_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/mk48t59.h linux/include/asm-ppc/mk48t59.h
--- v2.2.7/linux/include/asm-ppc/mk48t59.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/mk48t59.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,35 @@
+/*
+ * Registers for the mk48t59 real-time-clock
+ */
+
+#ifndef _PPC_MK48T59_H
+#define _PPC_MK48T59_H
+
+/* RTC Offsets */
+
+#define MK48T59_RTC_SECONDS		0x1FF9
+#define MK48T59_RTC_MINUTES		0x1FFA
+#define MK48T59_RTC_HOURS		0x1FFB
+#define MK48T59_RTC_DAY_OF_WEEK		0x1FFC
+#define MK48T59_RTC_DAY_OF_MONTH	0x1FFD
+#define MK48T59_RTC_MONTH		0x1FFE
+#define MK48T59_RTC_YEAR		0x1FFF
+
+#define MK48T59_RTC_CONTROLA		0x1FF8
+#define MK48T59_RTC_CA_WRITE		0x80
+#define MK48T59_RTC_CA_READ		0x40
+#define MK48T59_RTC_CA_CALIB_SIGN	0x20
+#define MK48T59_RTC_CA_CALIB_MASK	0x1f
+
+#define MK48T59_RTC_CONTROLB		0x1FF9
+#define MK48T59_RTC_CB_STOP		0x80
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+#endif /* _PPC_MK48T59_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.2.7/linux/include/asm-ppc/page.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/page.h	Thu Apr 29 12:39:01 1999
@@ -9,7 +9,7 @@
X #define PAGE_MASK	(~(PAGE_SIZE-1))
X 
X #define PAGE_OFFSET	0xc0000000
-
+#define KERNELBASE	PAGE_OFFSET
X 
X #ifndef __ASSEMBLY__
X #ifdef __KERNEL__
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.2.7/linux/include/asm-ppc/pgtable.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/pgtable.h	Thu Apr 29 12:39:01 1999
@@ -37,6 +37,7 @@
X 
X extern unsigned long va_to_phys(unsigned long address);
X extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
X #endif /* __ASSEMBLY__ */
X /*
X  * The PowerPC MMU uses a hash table containing PTEs, together with
@@ -95,16 +96,19 @@
X  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
X  * area for the same reason. ;)
X  *
- * The vmalloc_offset MUST be larger than the gap between the bat2 mapping
- * and the size of physical ram.  Since the bat2 mapping can be larger than
- * the amount of ram we have vmalloc_offset must ensure that we don't try
- * to allocate areas that don't exist! This value of 64M will only cause
- * problems when we have >128M -- Cort
+ * We no longer map larger than phys RAM with the BATs so we don't have
+ * to worry about the VMALLOC_OFFSET causing problems.  We do have to worry
+ * about clashes between our early calls to ioremap() that start growing down
+ * from ioremap_base being run into the VM area allocations (growing upwards
+ * from VMALLOC_START).  For this reason we have ioremap_bot to check when
+ * we actually run into our mappings setup in the early boot with the VM
+ * system.  This really does become a problem for machines with good amounts
+ * of RAM.  -- Cort
X  */
-#define VMALLOC_OFFSET	(0x4000000) /* 64M */
+#define VMALLOC_OFFSET (0x4000000) /* 64M */
X #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
X #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END	0xf0000000
+#define VMALLOC_END	ioremap_bot
X 
X /*
X  * Bits in a linux-style PTE.  These match the bits in the
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- v2.2.7/linux/include/asm-ppc/pmu.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/pmu.h	Thu Apr 29 12:39:01 1999
@@ -64,11 +64,12 @@
X #define PMU_IOC_GET_MODEL	_IOR('B', 3, sizeof(__u32*))
X 
X #ifdef __KERNEL__
+
X void find_via_pmu(void);
X void via_pmu_init(void);
+
X int pmu_request(struct adb_request *req,
X 		void (*done)(struct adb_request *), int nbytes, ...);
-int pmu_send_request(struct adb_request *req);
X void pmu_poll(void);
X 
X void pmu_enable_backlight(int on);
@@ -79,6 +80,7 @@
X void pmu_restart(void);
X void pmu_shutdown(void);
X 
+int pmu_present(void);
X int pmu_get_model(void);
X 
X /*
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/posix_types.h linux/include/asm-ppc/posix_types.h
--- v2.2.7/linux/include/asm-ppc/posix_types.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/posix_types.h	Thu Apr 29 12:39:01 1999
@@ -43,7 +43,8 @@
X 
X #else /* __GNUC__ */
X 
-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ <= 2)
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \
+    || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
X /* With GNU C, use inline functions instead so args are evaluated only once: */
X 
X #undef __FD_SET
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/prep_nvram.h linux/include/asm-ppc/prep_nvram.h
--- v2.2.7/linux/include/asm-ppc/prep_nvram.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/prep_nvram.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,146 @@
+/*
+ * PreP compliant NVRAM access
+ */
+
+/* Corey Minyard (min...@acm.org) - Stolen from PReP book.   Per the
+   license I must say:
+     (C) Copyright (Corey Minyard), (1998).  All rights reserved
+ */
+
+/* Structure map for NVRAM on PowerPC Reference Platform */
+/* All fields are either character/byte strings which are valid either
+  endian or they are big-endian numbers.
+
+  There are a number of Date and Time fields which are in RTC format,
+  big-endian. These are stored in UT (GMT).
+
+  For enum's: if given in hex then they are bit significant, i.e. only
+  one bit is on for each enum.
+*/
+#ifndef _PPC_PREP_NVRAM_H
+#define _PPC_PREP_NVRAM_H
+
+#define NVSIZE 4096	/* size of NVRAM */
+#define OSAREASIZE 512	/* size of OSArea space */
+#define CONFSIZE 1024	/* guess at size of Configuration space */
+
+typedef struct _SECURITY {
+  unsigned long BootErrCnt;	    /* Count of boot password errors */
+  unsigned long ConfigErrCnt;	    /* Count of config password errors */
+  unsigned long BootErrorDT[2];	    /* Date&Time from RTC of last error in pw */
+  unsigned long ConfigErrorDT[2];   /* Date&Time from RTC of last error in pw */
+  unsigned long BootCorrectDT[2];   /* Date&Time from RTC of last correct pw */
+  unsigned long ConfigCorrectDT[2]; /* Date&Time from RTC of last correct pw */
+  unsigned long BootSetDT[2];	    /* Date&Time from RTC of last set of pw */
+  unsigned long ConfigSetDT[2];	    /* Date&Time from RTC of last set of pw */
+  unsigned char Serial[16];	    /* Box serial number */
+} SECURITY;
+
+typedef enum _OS_ID {
+  Unknown = 0,
+  Firmware = 1,
+  AIX = 2,
+  NT = 3,
+  MKOS2 = 4,
+  MKAIX = 5,
+  Taligent = 6,
+  Solaris = 7,
+  MK = 12
+} OS_ID;
+
+typedef struct _ERROR_LOG {
+  unsigned char ErrorLogEntry[40]; /* To be architected */
+} ERROR_LOG;
+
+typedef enum _BOOT_STATUS {
+  BootStarted = 0x01,
+  BootFinished = 0x02,
+  RestartStarted = 0x04,
+  RestartFinished = 0x08,
+  PowerFailStarted = 0x10,
+  PowerFailFinished = 0x20,
+  ProcessorReady = 0x40,
+  ProcessorRunning = 0x80,
+  ProcessorStart = 0x0100
+} BOOT_STATUS;
+
+typedef struct _RESTART_BLOCK {
+  unsigned short Version;
+  unsigned short Revision;
+  unsigned long ResumeReserve1[2];
+  volatile unsigned long BootStatus;
+  unsigned long CheckSum; /* Checksum of RESTART_BLOCK */
+  void * RestartAddress;
+  void * SaveAreaAddr;
+  unsigned long SaveAreaLength;
+} RESTART_BLOCK;
+
+typedef enum _OSAREA_USAGE {
+  Empty = 0,
+  Used = 1
+} OSAREA_USAGE;
+
+typedef enum _PM_MODE {
+  Suspend = 0x80, /* Part of state is in memory */
+  Normal = 0x00   /* No power management in effect */
+} PMMode;
+
+typedef struct _HEADER {
+  unsigned short Size;       /* NVRAM size in K(1024) */
+  unsigned char Version;     /* Structure map different */
+  unsigned char Revision;    /* Structure map the same -may
+                                be new values in old fields
+                                in other words old code still works */
+  unsigned short Crc1;       /* check sum from beginning of nvram to OSArea */
+  unsigned short Crc2;       /* check sum of config */
+  unsigned char LastOS;      /* OS_ID */
+  unsigned char Endian;      /* B if big endian, L if little endian */
+  unsigned char OSAreaUsage; /* OSAREA_USAGE */
+  unsigned char PMMode;      /* Shutdown mode */
+  RESTART_BLOCK RestartBlock;
+  SECURITY Security;
+  ERROR_LOG ErrorLog[2];
+
+  /* Global Environment information */
+  void * GEAddress;
+  unsigned long GELength;
+
+  /* Date&Time from RTC of last change to Global Environment */
+  unsigned long GELastWriteDT[2];
+
+  /* Configuration information */
+  void * ConfigAddress;
+  unsigned long ConfigLength;
+
+  /* Date&Time from RTC of last change to Configuration */
+  unsigned long ConfigLastWriteDT[2];
+  unsigned long ConfigCount; /* Count of entries in Configuration */
+
+  /* OS dependent temp area */
+  void * OSAreaAddress;
+  unsigned long OSAreaLength;
+
+  /* Date&Time from RTC of last change to OSAreaArea */
+  unsigned long OSAreaLastWriteDT[2];
+} HEADER;
+
+/* Here is the whole map of the NVRAM */
+typedef struct _NVRAM_MAP {
+  HEADER Header;
+  unsigned char GEArea[NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER)];
+  unsigned char OSArea[OSAREASIZE];
+  unsigned char ConfigArea[CONFSIZE];
+} NVRAM_MAP;
+
+/* Routines to manipulate the NVRAM */
+void init_prep_nvram(void);
+char *prep_nvram_get_var(const char *name);
+char *prep_nvram_first_var(void);
+char *prep_nvram_next_var(char *name);
+
+/* Routines to read and write directly to the NVRAM */
+unsigned char prep_nvram_read_val(int addr);
+void prep_nvram_write_val(int           addr,
+			  unsigned char val);
+
+#endif /* _PPC_PREP_NVRAM_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.2.7/linux/include/asm-ppc/processor.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/processor.h	Tue May 11 08:24:32 1999
@@ -175,67 +175,13 @@
X #define SR15	15
X 
X #ifndef __ASSEMBLY__
-/*
- * If we've configured for a specific machine set things
- * up so the compiler can optimize away the other parts.
- * -- Cort
- */
-#ifdef CONFIG_MACH_SPECIFIC
-#ifdef CONFIG_PREP
-#define _machine (_MACH_prep)
-#define is_prep (1)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_CHRP
-#define _machine (_MACH_chrp)
-#define is_prep (0)
-#define is_chrp (1)
-#define have_of (1)
-#endif /* CONFIG_CHRP */
-
-#ifdef CONFIG_PMAC
-#define _machine (_MACH_Pmac)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (1)
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_MBX
-#define _machine (_MACH_mbx)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_MBX */
-
-#ifdef CONFIG_FADS
-#define _machine (_MACH_fads)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_FADS */
-
-#ifdef CONFIG_APUS
-#define _machine (_MACH_apus)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_APUS */
-
-#else /* CONFIG_MACH_SPECIFIC */
-
X extern int _machine;
X 
-/* if we're a prep machine */
-#define is_prep (_machine == _MACH_prep)
-
-/* if we're a chrp machine */
-#define is_chrp (_machine == _MACH_chrp)
-
-/* if we have openfirmware */
-extern unsigned long have_of;
-#endif /* CONFIG_MACH_SPECIFIC */
+/* Temporary hacks until we can clean things up better - Corey */
+extern int have_of;
+extern int is_prep;
+extern int is_chrp;
+extern int is_powerplus;
X 
X /* what kind of prep workstation we are */
X extern int _prep_type;
@@ -289,7 +235,6 @@
X 	double		fpr[32];	/* Complete floating point set */
X 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
X 	unsigned long	fpscr;		/* Floating point status */
-	unsigned long	smp_fork_ret;
X };
X 
X #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
@@ -301,7 +246,7 @@
X 	(struct pt_regs *)INIT_SP - 1, /* regs */ \
X 	KERNEL_DS, /*fs*/ \
X 	0, /* last_syscall */ \
-	{0}, 0, 0, 0 \
+	{0}, 0, 0 \
X }
X 
X /*
@@ -338,14 +283,10 @@
X #define init_task	(init_task_union.task)
X #define init_stack	(init_task_union.stack)
X 
+/* In misc.c */
+void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+
X #endif /* ndef ASSEMBLY*/
X 
X   
X #endif /* __ASM_PPC_PROCESSOR_H */
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/raven.h linux/include/asm-ppc/raven.h
--- v2.2.7/linux/include/asm-ppc/raven.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/raven.h	Tue May 11 08:24:32 1999
@@ -0,0 +1,33 @@
+/*
+ *  asm-ppc/raven.h -- Raven MPIC chip.
+ *
+ *  Copyright (C) 1998 Johnnie Peters
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#ifndef _ASMPPC_RAVEN_H
+#define _ASMPPC_RAVEN_H
+
+#define MVME2600_INT_SIO		0
+#define MVME2600_INT_FALCN_ECC_ERR	1
+#define MVME2600_INT_PCI_ETHERNET	2
+#define MVME2600_INT_PCI_SCSI		3
+#define MVME2600_INT_PCI_GRAPHICS	4
+#define MVME2600_INT_PCI_VME0		5
+#define MVME2600_INT_PCI_VME1		6
+#define MVME2600_INT_PCI_VME2		7
+#define MVME2600_INT_PCI_VME3		8
+#define MVME2600_INT_PCI_INTA		9
+#define MVME2600_INT_PCI_INTB		10
+#define MVME2600_INT_PCI_INTC 		11
+#define MVME2600_INT_PCI_INTD 		12
+#define MVME2600_INT_LM_SIG0		13
+#define MVME2600_INT_LM_SIG1		14
+
+extern struct hw_interrupt_type raven_pic;
+
+extern int raven_init(void);
+#endif _ASMPPC_RAVEN_H
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.2.7/linux/include/asm-ppc/smp.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/smp.h	Thu Apr 29 12:39:07 1999
@@ -27,6 +27,7 @@
X 
X extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
X extern void smp_store_cpu_info(int id);
+extern void smp_message_recv(void);
X 
X #define NO_PROC_ID		0xFF            /* No processor magic marker */
X #define PROC_CHANGE_PENALTY	20
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.2.7/linux/include/asm-ppc/softirq.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/softirq.h	Thu Apr 29 12:39:07 1999
@@ -4,7 +4,7 @@
X #include <asm/atomic.h>
X #include <asm/hardirq.h>
X 
-extern unsigned int local_bh_count[NR_CPUS];
+extern unsigned int ppc_local_bh_count[NR_CPUS];
X 
X #define get_active_bhs()	(bh_mask & bh_active)
X #define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
@@ -29,6 +29,7 @@
X }
X 
X #ifdef __SMP__
+
X /*
X  * The locking mechanism for base handlers, to prevent re-entrancy,
X  * is entirely private to an implementation, it should not be
@@ -55,7 +56,7 @@
X {
X 	if (!test_and_set_bit(0,&global_bh_count)) {
X 		if (atomic_read(&global_bh_lock) == 0) {
-			++local_bh_count[cpu];
+			++ppc_local_bh_count[cpu];
X 			return 1;
X 		}
X 		clear_bit(0,&global_bh_count);
@@ -65,30 +66,30 @@
X 
X static inline void softirq_endlock(int cpu)
X {
-	local_bh_count[cpu]--;
+	ppc_local_bh_count[cpu]--;
X 	clear_bit(0,&global_bh_count);
X }
X 
-#else /* __SMP__ */
+#else
X 
X extern inline void start_bh_atomic(void)
X {
-	local_bh_count[smp_processor_id()]++;
+	ppc_local_bh_count[smp_processor_id()]++;
X 	barrier();
X }
X 
X extern inline void end_bh_atomic(void)
X {
X 	barrier();
-	local_bh_count[smp_processor_id()]--;
+	ppc_local_bh_count[smp_processor_id()]--;
X }
X 
X /* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)	(local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
-#define softirq_endlock(cpu)	(local_bh_count[cpu] = 0)
-#define synchronize_bh()	do { } while (0)
+#define softirq_trylock(cpu)	(ppc_local_bh_count[cpu] ? 0 : (ppc_local_bh_count[cpu]=1))
+#define softirq_endlock(cpu)	(ppc_local_bh_count[cpu] = 0)
+#define synchronize_bh()	barrier()
X 
-#endif /* __SMP__ */
+#endif	/* SMP */
X 
X /*
X  * These use a mask count to correctly handle
@@ -107,4 +108,4 @@
X 		bh_mask |= 1 << nr;
X }
X 
-#endif
+#endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/string.h linux/include/asm-ppc/string.h
--- v2.2.7/linux/include/asm-ppc/string.h	Sat Aug 16 09:51:09 1997
+++ linux/include/asm-ppc/string.h	Thu Apr 29 12:39:07 1999
@@ -14,5 +14,6 @@
X #define __HAVE_ARCH_MEMCHR
X 
X extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, int);
X 
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.2.7/linux/include/asm-ppc/system.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/system.h	Tue May 11 08:24:32 1999
@@ -25,6 +25,9 @@
X #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
X #define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")
X 
+extern void xmon_irq(int, void *, struct pt_regs *);
+extern void xmon(struct pt_regs *excp);
+
X #define __save_flags(flags)	({\
X 	__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
X #define __save_and_cli(flags)	({__save_flags(flags);__cli();})
@@ -38,10 +41,10 @@
X 
X extern __inline__ void __restore_flags(unsigned long flags)
X {
-        extern atomic_t n_lost_interrupts;
+        extern atomic_t ppc_n_lost_interrupts;
X 	extern void do_lost_interrupts(unsigned long);
X 
-        if ((flags & MSR_EE) && atomic_read(&n_lost_interrupts) != 0) {
+        if ((flags & MSR_EE) && atomic_read(&ppc_n_lost_interrupts) != 0) {
X                 do_lost_interrupts(flags);
X         } else {
X                 __asm__ __volatile__ ("sync; mtmsr %0; isync"
@@ -68,8 +71,8 @@
X extern void pmac_nvram_init(void);
X extern void read_rtc_time(void);
X extern void pmac_find_display(void);
-extern void giveup_fpu(void);
-extern void smp_giveup_fpu(struct task_struct *);
+extern void giveup_fpu(struct task_struct *);
+extern void enable_kernel_fp(void);
X extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
X extern void cvt_df(double *from, float *to, unsigned long *fpscr);
X 
@@ -77,11 +80,14 @@
X extern void note_scsi_host(struct device_node *, void *);
X 
X struct task_struct;
-extern void switch_to(struct task_struct *prev, struct task_struct *next);
+#define switch_to(prev,next,last) _switch_to((prev),(next),&(last))
+extern void _switch_to(struct task_struct *, struct task_struct *,
+		       struct task_struct **);
X 
X struct thread_struct;
-extern void _switch(struct thread_struct *prev, struct thread_struct *next,
-		    unsigned long context);
+extern struct task_struct *_switch(struct thread_struct *prev,
+				     struct thread_struct *next,
+				     unsigned long context);
X 
X struct pt_regs;
X extern void dump_regs(struct pt_regs *);
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/vga.h linux/include/asm-ppc/vga.h
--- v2.2.7/linux/include/asm-ppc/vga.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/vga.h	Thu Apr 29 12:39:07 1999
@@ -46,7 +46,8 @@
X #define scr_memcpyw_from memcpy
X #define scr_memcpyw_to memcpy
X 
-#define VGA_MAP_MEM(x) (x + _ISA_MEM_BASE)
+extern unsigned long vgacon_remap_base;
+#define VGA_MAP_MEM(x) (x + vgacon_remap_base)
X #define vga_readb(x) (*(x))
X #define vga_writeb(x,y) (*(y) = (x))
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h
--- v2.2.7/linux/include/asm-sparc/siginfo.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-sparc/siginfo.h	Wed Apr 28 14:40:07 1999
@@ -1,4 +1,4 @@
-/* $Id: siginfo.h,v 1.3 1998/08/26 10:33:29 davem Exp $
+/* $Id: siginfo.h,v 1.4 1999/04/28 19:45:20 davem Exp $
X  * siginfo.c:
X  */
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.2.7/linux/include/asm-sparc/smp.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-sparc/smp.h	Tue May 11 08:24:32 1999
@@ -157,6 +157,7 @@
X #endif
X 
X #define smp_processor_id() hard_smp_processor_id()
+/* XXX We really need to implement this now.  -DaveM */
X extern __inline__ void smp_send_reschedule(int cpu) { }
X extern __inline__ void smp_send_stop(void) { }
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.2.7/linux/include/asm-sparc/system.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-sparc/system.h	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.73 1999/04/20 13:22:49 anton Exp $ */
+/* $Id: system.h,v 1.74 1999/05/08 03:03:14 davem Exp $ */
X #include <linux/config.h>
X 
X #ifndef __SPARC_SYSTEM_H
@@ -84,8 +84,15 @@
X #define SWITCH_DO_LAZY_FPU if(last_task_used_math != next) next->tss.kregs->psr&=~PSR_EF;
X #endif
X 
-	/* Much care has gone into this code, do not touch it. */
-#define switch_to(prev, next) do {							\
+	/* Much care has gone into this code, do not touch it.
+	 *
+	 * We need to loadup regs l0/l1 for the newly forked child
+	 * case because the trap return path relies on those registers
+	 * holding certain values, gcc is told that they are clobbered.
+	 * Gcc needs registers for 3 values in and 1 value out, so we
+	 * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
+	 */
+#define switch_to(prev, next, last) do {						\
X 	__label__ here;									\
X 	register unsigned long task_pc asm("o7");					\
X 	extern struct task_struct *current_set[NR_CPUS];				\
@@ -103,21 +110,22 @@
X 	next->mm->cpu_vm_mask |= (1 << smp_processor_id());				\
X 	task_pc = ((unsigned long) &&here) - 0x8;					\
X 	__asm__ __volatile__(								\
+	"mov	%%g6, %%g3\n\t"								\
X 	"rd	%%psr, %%g4\n\t"							\
-	"std	%%sp, [%%g6 + %3]\n\t"							\
+	"std	%%sp, [%%g6 + %4]\n\t"							\
X 	"rd	%%wim, %%g5\n\t"							\
X 	"wr	%%g4, 0x20, %%psr\n\t"							\
X 	"nop\n\t"									\
-	"std	%%g4, [%%g6 + %2]\n\t"							\
-	"ldd	[%1 + %2], %%g4\n\t"							\
-	"mov	%1, %%g6\n\t"								\
+	"std	%%g4, [%%g6 + %3]\n\t"							\
+	"ldd	[%2 + %3], %%g4\n\t"							\
+	"mov	%2, %%g6\n\t"								\
X 	".globl	patchme_store_new_current\n"						\
X "patchme_store_new_current:\n\t"							\
-	"st	%1, [%0]\n\t"								\
+	"st	%2, [%1]\n\t"								\
X 	"wr	%%g4, 0x20, %%psr\n\t"							\
X 	"nop\n\t"									\
X 	"nop\n\t"									\
-	"ldd	[%%g6 + %3], %%sp\n\t"							\
+	"ldd	[%%g6 + %4], %%sp\n\t"							\
X 	"wr	%%g5, 0x0, %%wim\n\t"							\
X 	"ldd	[%%sp + 0x00], %%l0\n\t"						\
X 	"ldd	[%%sp + 0x38], %%i6\n\t"						\
@@ -125,11 +133,13 @@
X 	"nop\n\t"									\
X 	"nop\n\t"									\
X 	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
-	" nop\n\t" : : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),	\
+	" mov	%%g3, %0\n\t"								\
+        : "=&r" (last)									\
+        : "r" (&(current_set[hard_smp_processor_id()])), "r" (next),			\
X 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),		\
X 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
X 	  "r" (task_pc)									\
-	: "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3",				\
+	: "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1",				\
X 	"l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2",	\
X 	"o3");										\
X here:  } while(0)
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.2.7/linux/include/asm-sparc64/mmu_context.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-sparc64/mmu_context.h	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.34 1999/01/11 13:45:44 davem Exp $ */
+/* $Id: mmu_context.h,v 1.35 1999/05/08 03:03:20 davem Exp $ */
X #ifndef __SPARC64_MMU_CONTEXT_H
X #define __SPARC64_MMU_CONTEXT_H
X 
@@ -13,7 +13,6 @@
X #ifndef __ASSEMBLY__
X 
X extern unsigned long tlb_context_cache;
-extern spinlock_t scheduler_lock;
X extern unsigned long mmu_context_bmap[];
X 
X #define CTX_VERSION_SHIFT	(PAGE_SHIFT - 3)
@@ -38,11 +37,9 @@
X #define destroy_context(__mm)	do { 						\
X 	if ((__mm)->context != NO_CONTEXT &&					\
X 	    atomic_read(&(__mm)->count) == 1) { 				\
-		spin_lock(&scheduler_lock); 					\
X 		if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
X 			clear_bit((__mm)->context & ~(CTX_VERSION_MASK),	\
X 				  mmu_context_bmap);				\
-		spin_unlock(&scheduler_lock); 					\
X 		(__mm)->context = NO_CONTEXT; 					\
X 		if(current->mm == (__mm)) {					\
X 			current->tss.ctx = 0;					\
@@ -126,9 +123,7 @@
X #define activate_context(__tsk)		\
X do {	flushw_user();			\
X 	(__tsk)->mm->cpu_vm_mask = 0;	\
-	spin_lock(&scheduler_lock);	\
X 	__get_mmu_context(__tsk);	\
-	spin_unlock(&scheduler_lock);	\
X 	(__tsk)->mm->cpu_vm_mask = (1UL<<smp_processor_id()); \
X } while(0)
X 
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.2.7/linux/include/asm-sparc64/system.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-sparc64/system.h	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.48 1999/01/02 16:50:28 davem Exp $ */
+/* $Id: system.h,v 1.50 1999/05/08 03:03:22 davem Exp $ */
X #ifndef __SPARC64_SYSTEM_H
X #define __SPARC64_SYSTEM_H
X 
@@ -48,7 +48,7 @@
X ({	unsigned long retval; \
X 	__asm__ __volatile__("rdpr	%%pil, %0\n\t" \
X 			     "wrpr	%1, %%pil" \
-			     : "=r" (retval) \
+			     : "=&r" (retval) \
X 			     : "r" (__new_pil) \
X 			     : "memory"); \
X 	retval; \
@@ -127,21 +127,14 @@
X 
X 	/* See what happens when you design the chip correctly?
X 	 *
-	 * XXX What we are doing here assumes a lot about gcc reload
-	 * XXX internals, it heavily risks compiler aborts due to
-	 * XXX forbidden registers being spilled.  Rewrite me...  -DaveM
-	 *
-	 * SMP NOTE: At first glance it looks like there is a tiny
-	 *           race window here at the end.  The possible problem
-	 *           would be if a tlbcachesync MONDO vector got delivered
-	 *           to us right before we set the final %g6 thread reg
-	 *           value.  But that is impossible since only the holder
-	 *           of scheduler_lock can send a tlbcachesync MONDO and
-	 *           by definition we hold it right now.  Normal tlb
-	 *           flush xcalls can come in, but those are safe and do
-	 *           not reference %g6.
+	 * We tell gcc we clobber all non-fixed-usage registers except
+	 * for l0/l1.  It will use one for 'next' and the other to hold
+	 * the output value of 'last'.  'next' is not referenced again
+	 * past the invocation of switch_to in the scheduler, so we need
+	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
+	 * and 2 stores in this critical code path.  -DaveM
X 	 */
-#define switch_to(prev, next)							\
+#define switch_to(prev, next, last)						\
X do {	if (current->tss.flags & SPARC_FLAG_PERFCTR) {				\
X 		unsigned long __tmp;						\
X 		read_pcr(__tmp);						\
@@ -157,26 +150,23 @@
X 	__get_mmu_context(next);						\
X 	(next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());			\
X 	__asm__ __volatile__(							\
+	"mov	%%g6, %%g5\n\t"							\
X 	"wrpr	%%g0, 0x95, %%pstate\n\t"					\
-	"stx	%%l0, [%%sp + 2047 + 0x60]\n\t"					\
-	"stx	%%l1, [%%sp + 2047 + 0x68]\n\t"					\
X 	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"					\
X 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"					\
X 	"rdpr	%%wstate, %%o5\n\t"						\
-	"stx	%%o6, [%%g6 + %2]\n\t"						\
-	"sth	%%o5, [%%g6 + %1]\n\t"						\
+	"stx	%%o6, [%%g6 + %3]\n\t"						\
+	"sth	%%o5, [%%g6 + %2]\n\t"						\
X 	"rdpr	%%cwp, %%o5\n\t"						\
-	"sth	%%o5, [%%g6 + %4]\n\t"						\
-	"mov	%0, %%g6\n\t"							\
-	"lduh	[%0 + %4], %%g1\n\t"						\
+	"sth	%%o5, [%%g6 + %5]\n\t"						\
+	"mov	%1, %%g6\n\t"							\
+	"lduh	[%1 + %5], %%g1\n\t"						\
X 	"wrpr	%%g1, %%cwp\n\t"						\
-	"ldx	[%%g6 + %2], %%o6\n\t"						\
-	"lduh	[%%g6 + %1], %%o5\n\t"						\
-	"lduh	[%%g6 + %3], %%o7\n\t"						\
+	"ldx	[%%g6 + %3], %%o6\n\t"						\
+	"lduh	[%%g6 + %2], %%o5\n\t"						\
+	"lduh	[%%g6 + %4], %%o7\n\t"						\
X 	"mov	%%g6, %%l2\n\t"							\
X 	"wrpr	%%o5, 0x0, %%wstate\n\t"					\
-	"ldx	[%%sp + 2047 + 0x60], %%l0\n\t"					\
-	"ldx	[%%sp + 2047 + 0x68], %%l1\n\t"					\
X 	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"					\
X 	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"					\
X 	"wrpr	%%g0, 0x94, %%pstate\n\t"					\
@@ -184,8 +174,8 @@
X 	"wrpr	%%g0, 0x96, %%pstate\n\t"					\
X 	"andcc	%%o7, 0x100, %%g0\n\t"						\
X 	"bne,pn	%%icc, ret_from_syscall\n\t"					\
-	" nop\n\t"								\
-	: 									\
+	" mov	%%g5, %0\n\t"							\
+	: "=&r" (last)								\
X 	: "r" (next),								\
X 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),	\
X 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),	\
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.2.7/linux/include/asm-sparc64/uaccess.h	Sun Nov  8 14:03:11 1998
+++ linux/include/asm-sparc64/uaccess.h	Tue May 11 08:24:32 1999
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */
+/* $Id: uaccess.h,v 1.29 1999/05/08 03:03:25 davem Exp $ */
X #ifndef _ASM_UACCESS_H
X #define _ASM_UACCESS_H
X 
@@ -41,12 +41,9 @@
X 
X #define segment_eq(a,b)  ((a).seg == (b).seg)
X 
-extern spinlock_t scheduler_lock;
-
X #define set_fs(val)								\
X do {										\
X 	if (current->tss.current_ds.seg != val.seg) {				\
-		spin_lock(&scheduler_lock);					\
X 		current->tss.current_ds = (val);				\
X 		if (segment_eq((val), KERNEL_DS)) {				\
X 			flushw_user ();						\
@@ -56,7 +53,6 @@
X 		}								\
X 		spitfire_set_secondary_context(current->tss.ctx); 		\
X 		__asm__ __volatile__("flush %g6");				\
-		spin_unlock(&scheduler_lock);					\
X 	}									\
X } while(0)
X 
diff -u --recursive --new-file v2.2.7/linux/include/linux/capability.h linux/include/linux/capability.h
--- v2.2.7/linux/include/linux/capability.h	Fri Oct 23 22:01:26 1998
+++ linux/include/linux/capability.h	Tue May 11 10:35:45 1999
@@ -193,7 +193,6 @@
X /* Allow device administration (mknod)*/
X /* Allow examination and configuration of disk quotas */
X /* Allow configuring the kernel's syslog (printk behaviour) */
-/* Allow sending a signal to any process */
X /* Allow setting the domainname */
X /* Allow setting the hostname */
X /* Allow calling bdflush() */
diff -u --recursive --new-file v2.2.7/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.2.7/linux/include/linux/dcache.h	Tue Mar 23 14:35:48 1999
+++ linux/include/linux/dcache.h	Sat May  8 17:56:37 1999
@@ -77,7 +77,7 @@
X };
X 
X struct dentry_operations {
-	int (*d_revalidate)(struct dentry *);
+	int (*d_revalidate)(struct dentry *, int);
X 	int (*d_hash) (struct dentry *, struct qstr *);
X 	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
X 	void (*d_delete)(struct dentry *);
diff -u --recursive --new-file v2.2.7/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.2.7/linux/include/linux/fs.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/fs.h	Tue May 11 10:35:44 1999
@@ -810,6 +810,18 @@
X #define PTR_ERR(ptr)	((long)(ptr))
X #define IS_ERR(ptr)	((unsigned long)(ptr) > (unsigned long)(-1000))
X 
+/*
+ * The bitmask for a lookup event:
+ *  - follow links at the end
+ *  - require a directory
+ *  - ending slashes ok even for nonexistent files
+ *  - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW		(1)
+#define LOOKUP_DIRECTORY	(2)
+#define LOOKUP_SLASHOK		(4)
+#define LOOKUP_CONTINUE		(8)
+
X extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
X extern struct dentry * __namei(const char *, unsigned int);
X 
diff -u --recursive --new-file v2.2.7/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.2.7/linux/include/linux/nfs_fs.h	Wed Mar 10 15:29:50 1999
+++ linux/include/linux/nfs_fs.h	Tue May 11 10:35:46 1999
@@ -181,6 +181,8 @@
X 				struct nfs_fattr *);
X extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
X extern int nfs_revalidate(struct dentry *);
+extern int nfs_open(struct inode *, struct file *);
+extern int nfs_release(struct inode *, struct file *);
X extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *);
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 31'
echo 'File patch-2.2.8 is continued in part 32'
echo 32 > _shar_seq_.tmp
#!/bin/sh
# this is part 32 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 32; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 
X /*
diff -u --recursive --new-file v2.2.7/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.2.7/linux/include/linux/pagemap.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/pagemap.h	Tue May 11 10:35:49 1999
@@ -17,6 +17,27 @@
X 	return PAGE_OFFSET + PAGE_SIZE * (page - mem_map);
X }
X 
+/*
+ * The page cache can done in larger chunks than
+ * one page, because it allows for more efficient
+ * throughput (it can then be mapped into user
+ * space in smaller chunks for same flexibility).
+ *
+ * Or rather, it _will_ be done in larger chunks.
+ */
+#define PAGE_CACHE_SHIFT	PAGE_SHIFT
+#define PAGE_CACHE_SIZE		PAGE_SIZE
+#define PAGE_CACHE_MASK		PAGE_MASK
+
+#define page_cache_alloc()	__get_free_page(GFP_USER)
+#define page_cache_free(x)	free_page(x)
+#define page_cache_release(x)	__free_page(x)
+
+/*
+ * From a kernel address, get the "struct page *"
+ */
+#define page_cache_entry(x)	(mem_map + MAP_NR(x))
+
X #define PAGE_HASH_BITS 12
X #define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
X 
diff -u --recursive --new-file v2.2.7/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.2.7/linux/include/linux/parport_pc.h	Fri Oct 23 22:01:27 1998
+++ linux/include/linux/parport_pc.h	Tue May 11 10:36:23 1999
@@ -14,8 +14,15 @@
X #define STATUS   0x1
X #define DATA     0
X 
+/* Private data for PC low-level driver. */
+struct parport_pc_private {
+	/* Contents of CTR. */
+	unsigned char ctr;
+};
+
X extern int parport_pc_epp_clear_timeout(struct parport *pb);
X 
+extern volatile unsigned char parport_pc_ctr;
X 
X extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
X {
@@ -62,19 +69,24 @@
X 
X extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
X {
+	struct parport_pc_private *priv = p->private_data;
+	priv->ctr = d;/* update soft copy */
X 	outb(d, p->base+CONTROL);
X }
X 
X extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
X {
-	return inb(p->base+CONTROL);
+	struct parport_pc_private *priv = p->private_data;
+	return priv->ctr;
X }
X 
X extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
X {
-	unsigned char old = inb(p->base+CONTROL);
-	outb(((old & ~mask) ^ val), p->base+CONTROL);
-	return old;
+	struct parport_pc_private *priv = p->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	outb (ctr, p->base+CONTROL);
+	return priv->ctr = ctr; /* update soft copy */
X }
X 
X extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
diff -u --recursive --new-file v2.2.7/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.2.7/linux/include/linux/sched.h	Mon Mar 29 11:09:12 1999
+++ linux/include/linux/sched.h	Tue May 11 10:35:45 1999
@@ -112,10 +112,10 @@
X  * a separate lock).
X  */
X extern rwlock_t tasklist_lock;
-extern spinlock_t scheduler_lock;
X extern spinlock_t runqueue_lock;
X 
X extern void sched_init(void);
+extern void init_idle(void);
X extern void show_state(void);
X extern void trap_init(void);
X 
diff -u --recursive --new-file v2.2.7/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.2.7/linux/include/linux/smp.h	Mon Dec 28 15:00:53 1998
+++ linux/include/linux/smp.h	Tue May 11 10:35:44 1999
@@ -42,6 +42,12 @@
X extern void smp_commence(void);
X 
X /*
+ * Call a function on all other processors
+ */
+extern int smp_call_function (void (*func) (void *info), void *info,
+			      int retry, int wait);
+
+/*
X  * True once the per process idle is forked
X  */
X extern int smp_threads_ready;
@@ -60,7 +66,7 @@
X 					 * when rebooting
X 					 */
X #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
-#define MSG_MTRR_CHANGE         0x0004  /* Change MTRR */
+#define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
X 
X #else
X 
@@ -68,12 +74,13 @@
X  *	These macros fold the SMP functionality into a single CPU system
X  */
X  
-#define smp_num_cpus			1
-#define smp_processor_id()		0
-#define hard_smp_processor_id()		0
-#define smp_threads_ready		1
+#define smp_num_cpus				1
+#define smp_processor_id()			0
+#define hard_smp_processor_id()			0
+#define smp_threads_ready			1
X #define kernel_lock()
-#define cpu_logical_map(cpu)		0
+#define cpu_logical_map(cpu)			0
+#define smp_call_function(func,info,retry,wait)
X 
X #endif
X #endif
diff -u --recursive --new-file v2.2.7/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.2.7/linux/include/linux/videodev.h	Tue Feb 23 15:21:35 1999
+++ linux/include/linux/videodev.h	Fri May  7 11:05:30 1999
@@ -95,6 +95,8 @@
X #define VIDEO_TUNER_LOW		8	/* Uses KHz not MHz */
X #define VIDEO_TUNER_NORM	16	/* Tuner can set norm */
X #define VIDEO_TUNER_STEREO_ON	128	/* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON      256     /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON      512     /* Tuner is seeing an MBS datastream */
X 	__u16 mode;			/* PAL/NTSC/SECAM/OTHER */
X #define VIDEO_MODE_PAL		0
X #define VIDEO_MODE_NTSC		1
@@ -275,6 +277,7 @@
X #define VID_HARDWARE_GEMTEK	18
X #define VID_HARDWARE_TYPHOON	19
X #define VID_HARDWARE_VINO	20	/* Reserved for SGI Indy Vino */
+#define VID_HARDWARE_CADET	21	/* Cadet radio */
X 
X /*
X  *	Initialiser list
diff -u --recursive --new-file v2.2.7/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.2.7/linux/include/net/tcp.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/tcp.h	Tue May 11 10:36:51 1999
@@ -174,6 +174,7 @@
X 	struct tcp_func		*af_specific;
X 	struct tcp_bind_bucket	*tb;
X 	struct tcp_tw_bucket	*next_death;
+	struct tcp_tw_bucket	**pprev_death;
X 	int			death_slot;
X #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
X 	struct in6_addr		v6_daddr;
@@ -714,6 +715,22 @@
X 	u32 new_win = __tcp_select_window(sk);
X 
X 	return (new_win && (new_win > (cur_win << 1)));
+}
+
+/* Recalculate snd_ssthresh, we want to set it to:
+ *
+ * 	one half the current congestion window, but no
+ *	less than two segments
+ *
+ * We must take into account the current send window
+ * as well, however we keep track of that using different
+ * units so a conversion is necessary.  -DaveM
+ */
+extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
+{
+	__u32 snd_wnd_packets = tp->snd_wnd / tp->mss_cache;
+
+	return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2);
X }
X 
X /* TCP timestamps are only 32-bits, this causes a slight
diff -u --recursive --new-file v2.2.7/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.2.7/linux/include/scsi/sg.h	Fri Apr 16 14:47:31 1999
+++ linux/include/scsi/sg.h	Fri May  7 11:05:30 1999
@@ -12,10 +12,16 @@
X *       Copyright (C) 1998, 1999 Douglas Gilbert
X 
X 
-    Version: 2.1.31 (990327)
+    Version: 2.1.32 (990501)
X     This version for later 2.1.x series and 2.2.x kernels
X     D. P. Gilbert (dgil...@interlog.com, do...@triode.net.au)
X 
+    Changes since 2.1.31 (990327)
+        - add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default
+          to _not_ flag underruns (affects aic7xxx driver)
+        - clean up logging of pointers to use %p (for 64 bit architectures)
+        - rework usage of get_user/copy_to_user family of kernel calls
+        - "disown" scsi_command blocks before releasing them
X     Changes since 2.1.30 (990320)
X         - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
X         -                increase max allowable mid-level pool usage
@@ -113,7 +119,7 @@
X  requesting 512KB) and scale them back in the face of ENOMEM errors.
X  N.B. Queuing up commands also ties up kernel memory.
X 
- More documentation can be found at www.netwinder.org/~dougg
+ More documentation can be found at www.torque.net/sg
X */
X 
X #define SG_MAX_SENSE 16   /* too little, unlikely to change in 2.2.x */
@@ -197,6 +203,11 @@
X #define SG_GET_COMMAND_Q 0x2270   /* Yields 0 (queuing off) or 1 (on) */
X #define SG_SET_COMMAND_Q 0x2271   /* Change queuing state with 0 or 1 */
X 
+/* Get/set whether DMA underrun will cause an error (DID_ERROR) [this only
+   currently applies to the [much-used] aic7xxx driver) */
+#define SG_GET_UNDERRUN_FLAG 0x2280 /* Yields 0 (don't flag) or 1 (flag) */
+#define SG_SET_UNDERRUN_FLAG 0x2281 /* Change flag underrun state */
+
X 
X #define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
X #define SG_DEFAULT_RETRIES 1
@@ -206,6 +217,7 @@
X #define SG_DEF_MERGE_FD 0       /* was 1 -> per device sequencing */
X #define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
X #define SG_DEF_FORCE_PACK_ID 0
+#define SG_DEF_UNDERRUN_FLAG 0
X 
X /* maximum outstanding requests, write() yields EDOM if exceeded */
X #define SG_MAX_QUEUE 16
diff -u --recursive --new-file v2.2.7/linux/init/main.c linux/init/main.c
--- v2.2.7/linux/init/main.c	Wed Apr 28 11:37:32 1999
+++ linux/init/main.c	Tue May 11 09:57:14 1999
@@ -46,6 +46,10 @@
X #include <linux/apm_bios.h>
X #endif
X 
+#ifdef CONFIG_MAC
+extern void nubus_init(void);
+#endif
+
X /*
X  * Versions of gcc older than that listed below may actually compile
X  * and link okay, but the end product can have subtle run time bugs.
@@ -74,7 +78,7 @@
X extern void uidcache_init(void);
X extern void mca_init(void);
X extern void sbus_init(void);
-extern void powermac_init(void);
+extern void ppc_init(void);
X extern void sysctl_init(void);
X extern void filescache_init(void);
X extern void signals_init(void);
@@ -354,7 +358,7 @@
X int rows, cols;
X 
X #ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load 2 = dual disk */
X extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
X extern int rd_size; /* Size of the ramdisk(s) */
X extern int rd_image_start;	/* starting block # of image */
@@ -578,6 +582,7 @@
X 	{ "no-hlt", no_halt },
X 	{ "no387", no_387 },
X 	{ "reboot=", reboot_setup },
+	{ "mca-pentium", mca_pentium },
X #endif
X #ifdef CONFIG_INET
X 	{ "ether=", eth_setup },
@@ -788,7 +793,8 @@
X #endif
X #if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) \
X 	    || defined(CONFIG_A4091_SCSI) || defined(CONFIG_MVME16x_SCSI) \
-	    || defined(CONFIG_BVME6000_SCSI)
+	    || defined(CONFIG_BVME6000_SCSI) \
+	    || defined(CONFIG_BLZ603EPLUS_SCSI)
X         { "53c7xx=", ncr53c7xx_setup },
X #endif
X #if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
@@ -901,7 +907,7 @@
X static void __init load_ramdisk(char *str, int *ints)
X {
X    if (ints[0] > 0 && ints[1] >= 0)
-      rd_doload = ints[1] & 1;
+      rd_doload = ints[1] & 3;
X }
X 
X static void __init prompt_ramdisk(char *str, int *ints)
@@ -1262,7 +1268,7 @@
X 	sbus_init();
X #endif
X #if defined(CONFIG_PPC)
-	powermac_init();
+	ppc_init();
X #endif
X #ifdef CONFIG_MCA
X 	mca_init();
@@ -1275,6 +1281,9 @@
X #endif
X #ifdef CONFIG_DIO
X 	dio_init();
+#endif
+#ifdef CONFIG_MAC
+	nubus_init();
X #endif
X 
X 	/* Networking initialization needs a process context */ 
diff -u --recursive --new-file v2.2.7/linux/ipc/shm.c linux/ipc/shm.c
--- v2.2.7/linux/ipc/shm.c	Wed Apr 28 11:37:32 1999
+++ linux/ipc/shm.c	Tue May  4 16:58:15 1999
@@ -634,7 +634,7 @@
X 
X 	pte = __pte(shp->shm_pages[idx]);
X 	if (!pte_present(pte)) {
-		unsigned long page = get_free_page(GFP_KERNEL);
+		unsigned long page = get_free_page(GFP_USER);
X 		if (!page) {
X 			oom(current);
X 			return 0;
diff -u --recursive --new-file v2.2.7/linux/kernel/exit.c linux/kernel/exit.c
--- v2.2.7/linux/kernel/exit.c	Tue Mar 23 14:35:48 1999
+++ linux/kernel/exit.c	Fri Apr 30 08:13:37 1999
@@ -32,9 +32,9 @@
X 		 */
X 		for (;;)  {
X 			int has_cpu;
-			spin_lock(&scheduler_lock);
+			spin_lock_irq(&runqueue_lock);
X 			has_cpu = p->has_cpu;
-			spin_unlock(&scheduler_lock);
+			spin_unlock_irq(&runqueue_lock);
X 			if (!has_cpu)
X 				break;
X 			do {
diff -u --recursive --new-file v2.2.7/linux/kernel/sched.c linux/kernel/sched.c
--- v2.2.7/linux/kernel/sched.c	Tue Mar 23 14:35:48 1999
+++ linux/kernel/sched.c	Mon May 10 09:55:21 1999
@@ -96,13 +96,156 @@
X  
X struct task_struct * task[NR_TASKS] = {&init_task, };
X 
+/*
+ * We align per-CPU scheduling data on cacheline boundaries,
+ * to prevent cacheline ping-pong.
+ */
+static union {
+	struct schedule_data {
+		struct task_struct * curr;
+		cycles_t last_schedule;
+	} schedule_data;
+	char __pad [SMP_CACHE_BYTES];
+} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}};
+
+#define cpu_curr(cpu) aligned_data[(cpu)].schedule_data.curr
+
X struct kernel_stat kstat = { 0 };
X 
+#ifdef __SMP__
+
+#define idle_task(cpu) (task[cpu_number_map[(cpu)]])
+#define can_schedule(p)	(!(p)->has_cpu)
+
+#else
+
+#define idle_task(cpu) (&init_task)
+#define can_schedule(p) (1)
+
+#endif
+
X void scheduling_functions_start_here(void) { }
X 
+/*
+ * This is the function that decides how desirable a process is..
+ * You can weigh different processes against each other depending
+ * on what CPU they've run on lately etc to try to handle cache
+ * and TLB miss penalties.
+ *
+ * Return values:
+ *	 -1000: never select this
+ *	     0: out of time, recalculate counters (but it might still be
+ *		selected)
+ *	   +ve: "goodness" value (the larger, the better)
+ *	 +1000: realtime process, select this.
+ */
+
+static inline int goodness (struct task_struct * prev,
+				 struct task_struct * p, int this_cpu)
+{
+	int weight;
+
+	/*
+	 * Realtime process, select the first one on the
+	 * runqueue (taking priorities within processes
+	 * into account).
+	 */
+	if (p->policy != SCHED_OTHER) {
+		weight = 1000 + p->rt_priority;
+		goto out;
+	}
+
+	/*
+	 * Give the process a first-approximation goodness value
+	 * according to the number of clock-ticks it has left.
+	 *
+	 * Don't do any other calculations if the time slice is
+	 * over..
+	 */
+	weight = p->counter;
+	if (!weight)
+		goto out;
+			
X #ifdef __SMP__
-static void reschedule_idle_slow(struct task_struct * p)
+	/* Give a largish advantage to the same processor...   */
+	/* (this is equivalent to penalizing other processors) */
+	if (p->processor == this_cpu)
+		weight += PROC_CHANGE_PENALTY;
+#endif
+
+	/* .. and a slight advantage to the current MM */
+	if (p->mm == prev->mm)
+		weight += 1;
+	weight += p->priority;
+
+out:
+	return weight;
+}
+
+/*
+ * subtle. We want to discard a yielded process only if it's being
+ * considered for a reschedule. Wakeup-time 'queries' of the scheduling
+ * state do not count. Another optimization we do: sched_yield()-ed
+ * processes are runnable (and thus will be considered for scheduling)
+ * right when they are calling schedule(). So the only place we need
+ * to care about SCHED_YIELD is when we calculate the previous process'
+ * goodness ...
+ */
+static inline int prev_goodness (struct task_struct * prev,
+					struct task_struct * p, int this_cpu)
+{
+	if (p->policy & SCHED_YIELD) {
+		p->policy &= ~SCHED_YIELD;
+		return 0;
+	}
+	return goodness(prev, p, this_cpu);
+}
+
+/*
+ * the 'goodness value' of replacing a process on a given CPU.
+ * positive value means 'replace', zero or negative means 'dont'.
+ */
+static inline int preemption_goodness (struct task_struct * prev,
+				struct task_struct * p, int cpu)
+{
+	return goodness(prev, p, cpu) - goodness(prev, prev, cpu);
+}
+
+/*
+ * If there is a dependency between p1 and p2,
+ * don't be too eager to go into the slow schedule.
+ * In particular, if p1 and p2 both want the kernel
+ * lock, there is no point in trying to make them
+ * extremely parallel..
+ *
+ * (No lock - lock_depth < 0)
+ *
+ * There are two additional metrics here:
+ *
+ * first, a 'cutoff' interval, currently 0-200 usecs on
+ * x86 CPUs, depending on the size of the 'SMP-local cache'.
+ * If the current process has longer average timeslices than
+ * this, then we utilize the idle CPU.
+ *
+ * second, if the wakeup comes from a process context,
+ * then the two processes are 'related'. (they form a
+ * 'gang')
+ *
+ * An idle CPU is almost always a bad thing, thus we skip
+ * the idle-CPU utilization only if both these conditions
+ * are true. (ie. a 'process-gang' rescheduling with rather
+ * high frequency should stay on the same CPU).
+ *
+ * [We can switch to something more finegrained in 2.3.]
+ *
+ * do not 'guess' if the to-be-scheduled task is RT.
+ */
+#define related(p1,p2) (((p1)->lock_depth >= 0) && (p2)->lock_depth >= 0) && \
+	(((p2)->policy == SCHED_OTHER) && ((p1)->avg_slice < cacheflush_time))
+
+static inline void reschedule_idle_slow(struct task_struct * p)
X {
+#ifdef __SMP__
X /*
X  * (see reschedule_idle() for an explanation first ...)
X  *
@@ -124,60 +267,71 @@
X  * 2.3. Also we can try to use the avg_slice value to predict
X  * 'likely reschedule' events even on other CPUs.]
X  */
-	int best_cpu = p->processor, this_cpu = smp_processor_id();
-	struct task_struct **idle = task, *tsk, *target_tsk;
-	int i = smp_num_cpus;
+	int this_cpu = smp_processor_id(), target_cpu;
+	struct task_struct *tsk, *target_tsk;
+	int cpu, best_cpu, weight, best_weight, i;
+	unsigned long flags;
+
+	best_weight = 0; /* prevents negative weight */
+
+	spin_lock_irqsave(&runqueue_lock, flags);
+
+	/*
+	 * shortcut if the woken up task's last CPU is
+	 * idle now.
+	 */
+	best_cpu = p->processor;
+	target_tsk = idle_task(best_cpu);
+	if (cpu_curr(best_cpu) == target_tsk)
+		goto send_now;
X 
X 	target_tsk = NULL;
-	do {
-		tsk = *idle;
-		idle++;
-		if (tsk->has_cpu) {
-			if (tsk->processor == this_cpu)
-				continue;
+	for (i = 0; i < smp_num_cpus; i++) {
+		cpu = cpu_logical_map(i);
+		tsk = cpu_curr(cpu);
+		if (related(tsk, p))
+			goto out_no_target;
+		weight = preemption_goodness(tsk, p, cpu);
+		if (weight > best_weight) {
+			best_weight = weight;
X 			target_tsk = tsk;
-			if (tsk->processor == best_cpu) {
-				/*
-				 * bingo, we couldnt get a better
-				 * CPU, activate it.
-				 */
-				goto send; /* this one helps GCC ... */
-			}
X 		}
-	} while (--i > 0);
+	}
X 
X 	/*
-	 * found any idle CPU?
+	 * found any suitable CPU?
X 	 */
-	if (target_tsk) {
-send:
-		target_tsk->need_resched = 1;
-		smp_send_reschedule(target_tsk->processor);
-		return;
-	}
+	if (!target_tsk)
+		goto out_no_target;
+		
+send_now:
+	target_cpu = target_tsk->processor;
+	target_tsk->need_resched = 1;
+	spin_unlock_irqrestore(&runqueue_lock, flags);
+	/*
+	 * the APIC stuff can go outside of the lock because
+	 * it uses no task information, only CPU#.
+	 */
+	if (target_cpu != this_cpu)
+		smp_send_reschedule(target_cpu);
+	return;
+out_no_target:
+	spin_unlock_irqrestore(&runqueue_lock, flags);
+	return;
+#else /* UP */
+	int this_cpu = smp_processor_id();
+	struct task_struct *tsk;
+
+	tsk = cpu_curr(this_cpu);
+	if (preemption_goodness(tsk, p, this_cpu) > 0)
+		tsk->need_resched = 1;
+#endif
X }
-#endif /* __SMP__ */
X 
-/*
- * If there is a dependency between p1 and p2,
- * don't be too eager to go into the slow schedule.
- * In particular, if p1 and p2 both want the kernel
- * lock, there is no point in trying to make them
- * extremely parallel..
- *
- * (No lock - lock_depth < 0)
- */
-#define related(p1,p2) ((p1)->lock_depth >= 0 && (p2)->lock_depth >= 0)
-
-static inline void reschedule_idle(struct task_struct * p)
+static void reschedule_idle(struct task_struct * p)
X {
-
-	if (p->policy != SCHED_OTHER || p->counter > current->counter + 3) {
-		current->need_resched = 1;
-		return;
-	}
-
X #ifdef __SMP__
+	int cpu = smp_processor_id();
X 	/*
X 	 * ("wakeup()" should not be called before we've initialized
X 	 * SMP completely.
@@ -187,35 +341,20 @@
X 	 *
X 	 * SMP rescheduling is done in 2 passes:
X 	 *  - pass #1: faster: 'quick decisions'
-	 *  - pass #2: slower: 'lets try and find another CPU'
+	 *  - pass #2: slower: 'lets try and find a suitable CPU'
X 	 */
X 
X 	/*
-	 * Pass #1
-	 *
-	 * There are two metrics here:
-	 *
-	 * first, a 'cutoff' interval, currently 0-200 usecs on
-	 * x86 CPUs, depending on the size of the 'SMP-local cache'.
-	 * If the current process has longer average timeslices than
-	 * this, then we utilize the idle CPU.
-	 *
-	 * second, if the wakeup comes from a process context,
-	 * then the two processes are 'related'. (they form a
-	 * 'gang')
-	 *
-	 * An idle CPU is almost always a bad thing, thus we skip
-	 * the idle-CPU utilization only if both these conditions
-	 * are true. (ie. a 'process-gang' rescheduling with rather
-	 * high frequency should stay on the same CPU).
-	 *
-	 * [We can switch to something more finegrained in 2.3.]
+	 * Pass #1. (subtle. We might be in the middle of __switch_to, so
+	 * to preserve scheduling atomicity we have to use cpu_curr)
X 	 */
-	if ((current->avg_slice < cacheflush_time) && related(current, p))
+	if ((p->processor == cpu) && related(cpu_curr(cpu), p))
X 		return;
-
-	reschedule_idle_slow(p);
X #endif /* __SMP__ */
+	/*
+	 * Pass #2
+	 */
+	reschedule_idle_slow(p);
X }
X 
X /*
@@ -291,7 +430,6 @@
X  * The run-queue lock locks the parts that actually access
X  * and change the run-queues, and have to be interrupt-safe.
X  */
-spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED;	/* should be acquired first */
X spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;  /* second */
X rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;	/* third */
X 
@@ -307,12 +445,19 @@
X {
X 	unsigned long flags;
X 
+	/*
+	 * We want the common case fall through straight, thus the goto.
+	 */
X 	spin_lock_irqsave(&runqueue_lock, flags);
X 	p->state = TASK_RUNNING;
-	if (!p->next_run) {
-		add_to_runqueue(p);
-		reschedule_idle(p);
-	}
+	if (p->next_run)
+		goto out;
+	add_to_runqueue(p);
+	spin_unlock_irqrestore(&runqueue_lock, flags);
+
+	reschedule_idle(p);
+	return;
+out:
X 	spin_unlock_irqrestore(&runqueue_lock, flags);
X }
X 
@@ -324,63 +469,6 @@
X }
X 
X /*
- * This is the function that decides how desirable a process is..
- * You can weigh different processes against each other depending
- * on what CPU they've run on lately etc to try to handle cache
- * and TLB miss penalties.
- *
- * Return values:
- *	 -1000: never select this
- *	     0: out of time, recalculate counters (but it might still be
- *		selected)
- *	   +ve: "goodness" value (the larger, the better)
- *	 +1000: realtime process, select this.
- */
-static inline int goodness(struct task_struct * p, struct task_struct * prev, int this_cpu)
-{
-	int policy = p->policy;
-	int weight;
-
-	if (policy & SCHED_YIELD) {
-		p->policy = policy & ~SCHED_YIELD;
-		return 0;
-	}
-
-	/*
-	 * Realtime process, select the first one on the
-	 * runqueue (taking priorities within processes
-	 * into account).
-	 */
-	if (policy != SCHED_OTHER)
-		return 1000 + p->rt_priority;
-
-	/*
-	 * Give the process a first-approximation goodness value
-	 * according to the number of clock-ticks it has left.
-	 *
-	 * Don't do any other calculations if the time slice is
-	 * over..
-	 */
-	weight = p->counter;
-	if (weight) {
-			
-#ifdef __SMP__
-		/* Give a largish advantage to the same processor...   */
-		/* (this is equivalent to penalizing other processors) */
-		if (p->processor == this_cpu)
-			weight += PROC_CHANGE_PENALTY;
-#endif
-
-		/* .. and a slight advantage to the current thread */
-		if (p->mm == prev->mm)
-			weight += 1;
-		weight += p->priority;
-	}
-
-	return weight;
-}
-
-/*
X  * Event timer code
X  */
X #define TVN_BITS 6
@@ -513,18 +601,6 @@
X 	return ret;
X }
X 
-#ifdef __SMP__
-
-#define idle_task (task[cpu_number_map[this_cpu]])
-#define can_schedule(p)	(!(p)->has_cpu)
-
-#else
-
-#define idle_task (&init_task)
-#define can_schedule(p) (1)
-
-#endif
-
X signed long schedule_timeout(signed long timeout)
X {
X 	struct timer_list timer;
@@ -577,60 +653,24 @@
X }
X 
X /*
- * This one aligns per-CPU data on cacheline boundaries.
+ * schedule_tail() is getting called from the fork return path. This
+ * cleans up all remaining scheduler things, without impacting the
+ * common case.
X  */
-static union {
-	struct schedule_data {
-		struct task_struct * prev;
-		long prevstate;
-		cycles_t last_schedule;
-	} schedule_data;
-	char __pad [SMP_CACHE_BYTES];
-} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}};
-
-
-static inline void __schedule_tail (void)
+static inline void __schedule_tail (struct task_struct *prev)
X {
X #ifdef __SMP__
-	struct schedule_data * sched_data;
-
-	/*
-	 * We might have switched CPUs:
-	 */
-	sched_data = & aligned_data[smp_processor_id()].schedule_data;
-
-	/*
-	 * Subtle. In the rare event that we got a wakeup to 'prev' just
-	 * during the reschedule (this is possible, the scheduler is pretty
-	 * parallel), we should do another reschedule in the next task's
-	 * context. schedule() will do the right thing next time around.
-	 * this is equivalent to 'delaying' the wakeup until the reschedule
-	 * has finished.
-	 */
-	if (sched_data->prev->state != sched_data->prevstate)
-		current->need_resched = 1;
-
-	/*
-	 * Release the previous process ...
-	 *
-	 * We have dropped all locks, and we must make sure that we
-	 * only mark the previous process as no longer having a CPU
-	 * after all other state has been seen by other CPU's. Thus
-	 * the write memory barrier!
-	 */
+	if ((prev->state == TASK_RUNNING) &&
+			(prev != idle_task(smp_processor_id())))
+		reschedule_idle(prev);
X 	wmb();
-	sched_data->prev->has_cpu = 0;
+	prev->has_cpu = 0;
X #endif /* __SMP__ */
X }
X 
-/*
- * schedule_tail() is getting called from the fork return path. This
- * cleans up all remaining scheduler things, without impacting the
- * common case.
- */
-void schedule_tail (void)
+void schedule_tail (struct task_struct *prev)
X {
-	__schedule_tail();
+	__schedule_tail(prev);
X }
X 
X /*
@@ -646,37 +686,38 @@
X asmlinkage void schedule(void)
X {
X 	struct schedule_data * sched_data;
-	struct task_struct * prev, * next;
-	int this_cpu;
+	struct task_struct *prev, *next, *p;
+	int this_cpu, c;
X 
-	run_task_queue(&tq_scheduler);
+	if (tq_scheduler)
+		goto handle_tq_scheduler;
+tq_scheduler_back:
X 
X 	prev = current;
X 	this_cpu = prev->processor;
-	/*
-	 * 'sched_data' is protected by the fact that we can run
-	 * only one process per CPU.
-	 */
-	sched_data = & aligned_data[this_cpu].schedule_data;
X 
X 	if (in_interrupt())
X 		goto scheduling_in_interrupt;
+
X 	release_kernel_lock(prev, this_cpu);
X 
X 	/* Do "administrative" work here while we don't hold any locks */
-	if (bh_active & bh_mask)
-		do_bottom_half();
+	if (bh_mask & bh_active)
+		goto handle_bh;
+handle_bh_back:
+
+	/*
+	 * 'sched_data' is protected by the fact that we can run
+	 * only one process per CPU.
+	 */
+	sched_data = & aligned_data[this_cpu].schedule_data;
X 
-	spin_lock(&scheduler_lock);
X 	spin_lock_irq(&runqueue_lock);
X 
X 	/* move an exhausted RR process to be last.. */
-	prev->need_resched = 0;
-
-	if (!prev->counter && prev->policy == SCHED_RR) {
-		prev->counter = prev->priority;
-		move_last_runqueue(prev);
-	}
+	if (prev->policy == SCHED_RR)
+		goto move_rr_last;
+move_rr_back:
X 
X 	switch (prev->state) {
X 		case TASK_INTERRUPTIBLE:
@@ -688,62 +729,72 @@
X 			del_from_runqueue(prev);
X 		case TASK_RUNNING:
X 	}
+	prev->need_resched = 0;
X 
-	sched_data->prevstate = prev->state;
+repeat_schedule:
X 
-/* this is the scheduler proper: */
-	{
-		struct task_struct * p = init_task.next_run;
-		int c = -1000;
+	/*
+	 * this is the scheduler proper:
+	 */
X 
-		/* Default process to select.. */
-		next = idle_task;
-		if (prev->state == TASK_RUNNING) {
-			c = goodness(prev, prev, this_cpu);
-			next = prev;
-		}
+	p = init_task.next_run;
+	/* Default process to select.. */
+	next = idle_task(this_cpu);
+	c = -1000;
+	if (prev->state == TASK_RUNNING)
+		goto still_running;
+still_running_back:
X 
-		/*
-		 * This is subtle.
-		 * Note how we can enable interrupts here, even
-		 * though interrupts can add processes to the run-
-		 * queue. This is because any new processes will
-		 * be added to the front of the queue, so "p" above
-		 * is a safe starting point.
-		 * run-queue deletion and re-ordering is protected by
-		 * the scheduler lock
-		 */
-		spin_unlock_irq(&runqueue_lock);
+	/*
+	 * This is subtle.
+	 * Note how we can enable interrupts here, even
+	 * though interrupts can add processes to the run-
+	 * queue. This is because any new processes will
+	 * be added to the front of the queue, so "p" above
+	 * is a safe starting point.
+	 * run-queue deletion and re-ordering is protected by
+	 * the scheduler lock
+	 */
X /*
X  * Note! there may appear new tasks on the run-queue during this, as
X  * interrupts are enabled. However, they will be put on front of the
X  * list, so our list starting at "p" is essentially fixed.
X  */
-		while (p != &init_task) {
-			if (can_schedule(p)) {
-				int weight = goodness(p, prev, this_cpu);
-				if (weight > c)
-					c = weight, next = p;
-			}
-			p = p->next_run;
-		}
-
-		/* Do we need to re-calculate counters? */
-		if (!c) {
-			struct task_struct *p;
-			read_lock(&tasklist_lock);
-			for_each_task(p)
-				p->counter = (p->counter >> 1) + p->priority;
-			read_unlock(&tasklist_lock);
+	while (p != &init_task) {
+		if (can_schedule(p)) {
+			int weight = goodness(prev, p, this_cpu);
+			if (weight > c)
+				c = weight, next = p;
X 		}
+		p = p->next_run;
X 	}
X 
+	/* Do we need to re-calculate counters? */
+	if (!c)
+		goto recalculate;
+	/*
+	 * from this point on nothing can prevent us from
+	 * switching to the next task, save this fact in
+	 * sched_data.
+	 */
+	sched_data->curr = next;
+#ifdef __SMP__
+ 	next->has_cpu = 1;
+	next->processor = this_cpu;
+#endif
+	spin_unlock_irq(&runqueue_lock);
+
+	if (prev == next)
+		goto same_process;
+
+#ifdef __SMP__
X  	/*
X  	 * maintain the per-process 'average timeslice' value.
X  	 * (this has to be recalculated even if we reschedule to
- 	 * the same process) Currently this is only used on SMP:
+ 	 * the same process) Currently this is only used on SMP,
+	 * and it's approximate, so we do not have to maintain
+	 * it while holding the runqueue spinlock.
X  	 */
-#ifdef __SMP__
X 	{
X 		cycles_t t, this_slice;
X 
@@ -752,10 +803,11 @@
X 		sched_data->last_schedule = t;
X 
X 		/*
-		 * Simple, exponentially fading average calculation:
+		 * Exponentially fading average calculation, with
+		 * some weight so it doesnt get fooled easily by
+		 * smaller irregularities.
X 		 */
-		prev->avg_slice = this_slice + prev->avg_slice;
-		prev->avg_slice >>= 1;
+		prev->avg_slice = (this_slice*1 + prev->avg_slice*1)/2;
X 	}
X 
X 	/*
@@ -763,27 +815,55 @@
X 	 * thus we have to lock the previous process from getting
X 	 * rescheduled during switch_to().
X 	 */
- 	next->processor = this_cpu;
- 	next->has_cpu = 1;
-	spin_unlock(&scheduler_lock);
+
X #endif /* __SMP__ */
- 	if (prev != next) {
-#ifdef __SMP__
-		sched_data->prev = prev;
-#endif
-	 	kstat.context_swtch++;
-		get_mmu_context(next);
-		switch_to(prev,next);
X 
-		__schedule_tail();
-	}
+	kstat.context_swtch++;
+	get_mmu_context(next);
+	switch_to(prev, next, prev);
+	__schedule_tail(prev);
+
+same_process:
X   
X 	reacquire_kernel_lock(current);
X 	return;
X 
+recalculate:
+	{
+		struct task_struct *p;
+		spin_unlock_irq(&runqueue_lock);
+		read_lock(&tasklist_lock);
+		for_each_task(p)
+			p->counter = (p->counter >> 1) + p->priority;
+		read_unlock(&tasklist_lock);
+		spin_lock_irq(&runqueue_lock);
+		goto repeat_schedule;
+	}
+
+still_running:
+	c = prev_goodness(prev, prev, this_cpu);
+	next = prev;
+	goto still_running_back;
+
+handle_bh:
+	do_bottom_half();
+	goto handle_bh_back;
+
+handle_tq_scheduler:
+	run_task_queue(&tq_scheduler);
+	goto tq_scheduler_back;
+
+move_rr_last:
+	if (!prev->counter) {
+		prev->counter = prev->priority;
+		move_last_runqueue(prev);
+	}
+	goto move_rr_back;
+
X scheduling_in_interrupt:
X 	printk("Scheduling in interrupt\n");
X 	*(int *)0 = 0;
+	return;
X }
X 
X rwlock_t waitqueue_lock = RW_LOCK_UNLOCKED;
@@ -798,21 +878,42 @@
X  */
X void __wake_up(struct wait_queue **q, unsigned int mode)
X {
-	struct wait_queue *next;
+	struct task_struct *p;
+	struct wait_queue *head, *next;
+
+        if (!q)
+		goto out;
+	/*
+	 * this is safe to be done before the check because it
+	 * means no deference, just pointer operations.
+	 */
+	head = WAIT_QUEUE_HEAD(q);
X 
X 	read_lock(&waitqueue_lock);
-	if (q && (next = *q)) {
-		struct wait_queue *head;
+	next = *q;
+	if (!next)
+		goto out_unlock;
X 
-		head = WAIT_QUEUE_HEAD(q);
-		while (next != head) {
-			struct task_struct *p = next->task;
-			next = next->next;
-			if (p->state & mode)
+	while (next != head) {
+		p = next->task;
+		next = next->next;
+		if (p->state & mode) {
+			/*
+			 * We can drop the read-lock early if this
+			 * is the only/last process.
+			 */
+			if (next == head) {
+				read_unlock(&waitqueue_lock);
X 				wake_up_process(p);
+				goto out;
+			}
+			wake_up_process(p);
X 		}
X 	}
+out_unlock:
X 	read_unlock(&waitqueue_lock);
+out:
+	return;
X }
X 
X /*
@@ -942,14 +1043,14 @@
X 
X #define	SLEEP_ON_HEAD					\
X 	wait.task = current;				\
-	write_lock_irqsave(&waitqueue_lock, flags);	\
+	write_lock_irqsave(&waitqueue_lock,flags);	\
X 	__add_wait_queue(p, &wait);			\
X 	write_unlock(&waitqueue_lock);
X 
X #define	SLEEP_ON_TAIL						\
X 	write_lock_irq(&waitqueue_lock);			\
X 	__remove_wait_queue(p, &wait);				\
-	write_unlock_irqrestore(&waitqueue_lock, flags);
+	write_unlock_irqrestore(&waitqueue_lock,flags);
X 
X void interruptible_sleep_on(struct wait_queue **p)
X {
@@ -1623,7 +1724,6 @@
X 	/*
X 	 * We play safe to avoid deadlocks.
X 	 */
-	spin_lock(&scheduler_lock);
X 	spin_lock_irq(&runqueue_lock);
X 	read_lock(&tasklist_lock);
X 
@@ -1671,7 +1771,6 @@
X out_unlock:
X 	read_unlock(&tasklist_lock);
X 	spin_unlock_irq(&runqueue_lock);
-	spin_unlock(&scheduler_lock);
X 
X out_nounlock:
X 	return retval;
@@ -1746,14 +1845,12 @@
X 
X asmlinkage int sys_sched_yield(void)
X {
-	spin_lock(&scheduler_lock);
X 	spin_lock_irq(&runqueue_lock);
X 	if (current->policy == SCHED_OTHER)
X 		current->policy |= SCHED_YIELD;
X 	current->need_resched = 1;
X 	move_last_runqueue(current);
X 	spin_unlock_irq(&runqueue_lock);
-	spin_unlock(&scheduler_lock);
X 	return 0;
X }
X 
@@ -1930,11 +2027,22 @@
X 	read_unlock(&tasklist_lock);
X }
X 
+void __init init_idle(void)
+{
+	cycles_t t;
+	struct schedule_data * sched_data;
+	sched_data = &aligned_data[smp_processor_id()].schedule_data;
+
+	t = get_cycles();
+	sched_data->curr = current;
+	sched_data->last_schedule = t;
+}
+
X void __init sched_init(void)
X {
X 	/*
-	 *	We have to do a little magic to get the first
-	 *	process right in SMP mode.
+	 * We have to do a little magic to get the first
+	 * process right in SMP mode.
X 	 */
X 	int cpu=hard_smp_processor_id();
X 	int nr = NR_TASKS;
diff -u --recursive --new-file v2.2.7/linux/kernel/signal.c linux/kernel/signal.c
--- v2.2.7/linux/kernel/signal.c	Mon Mar 29 11:09:12 1999
+++ linux/kernel/signal.c	Sun May  2 12:23:54 1999
@@ -265,7 +265,7 @@
X 	    && ((sig != SIGCONT) || (current->session != t->session))
X 	    && (current->euid ^ t->suid) && (current->euid ^ t->uid)
X 	    && (current->uid ^ t->suid) && (current->uid ^ t->uid)
-	    && !capable(CAP_SYS_ADMIN))
+	    && !capable(CAP_KILL))
X 		goto out_nolock;
X 
X 	/* The null signal is a permissions and process existance probe.
diff -u --recursive --new-file v2.2.7/linux/mm/filemap.c linux/mm/filemap.c
--- v2.2.7/linux/mm/filemap.c	Tue Mar 23 14:35:48 1999
+++ linux/mm/filemap.c	Tue May 11 08:51:13 1999
@@ -34,12 +34,6 @@
X unsigned long page_cache_size = 0;
X struct page * page_hash_table[PAGE_HASH_SIZE];
X 
-/*
- * Simple routines for both non-shared and shared mappings.
- */
-
-#define release_page(page) __free_page((page))
-
X /* 
X  * Define a request structure for outstanding page write requests
X  * to the background page io daemon
@@ -83,7 +77,7 @@
X 		page->prev = NULL;
X 		remove_page_from_hash_queue(page);
X 		page->inode = NULL;
-		__free_page(page);
+		page_cache_release(page);
X 		continue;
X 	}
X }
@@ -115,15 +109,15 @@
X 			page->prev = NULL;
X 			remove_page_from_hash_queue(page);
X 			page->inode = NULL;
-			__free_page(page);
+			page_cache_release(page);
X 			continue;
X 		}
X 		p = &page->next;
X 		offset = start - offset;
X 		/* partial truncate, clear end of page */
-		if (offset < PAGE_SIZE) {
+		if (offset < PAGE_CACHE_SIZE) {
X 			unsigned long address = page_address(page);
-			memset((void *) (offset + address), 0, PAGE_SIZE - offset);
+			memset((void *) (offset + address), 0, PAGE_CACHE_SIZE - offset);
X 			flush_page_to_ram(address);
X 		}
X 	}
@@ -136,7 +130,7 @@
X {
X 	remove_page_from_hash_queue(page);
X 	remove_page_from_inode_queue(page);
-	__free_page(page);
+	page_cache_release(page);
X }
X 
X int shrink_mmap(int priority, int gfp_mask)
@@ -226,9 +220,9 @@
X {
X 	unsigned long offset, len;
X 
-	offset = (pos & ~PAGE_MASK);
-	pos = pos & PAGE_MASK;
-	len = PAGE_SIZE - offset;
+	offset = (pos & ~PAGE_CACHE_MASK);
+	pos = pos & PAGE_CACHE_MASK;
+	len = PAGE_CACHE_SIZE - offset;
X 	do {
X 		struct page * page;
X 
@@ -238,13 +232,13 @@
X 		if (page) {
X 			wait_on_page(page);
X 			memcpy((void *) (offset + page_address(page)), buf, len);
-			release_page(page);
+			page_cache_release(page);
X 		}
X 		count -= len;
X 		buf += len;
-		len = PAGE_SIZE;
+		len = PAGE_CACHE_SIZE;
X 		offset = 0;
-		pos += PAGE_SIZE;
+		pos += PAGE_CACHE_SIZE;
X 	} while (count);
X }
X 
@@ -271,10 +265,10 @@
X 	struct page * page;
X 	struct page ** hash;
X 
-	offset &= PAGE_MASK;
+	offset &= PAGE_CACHE_MASK;
X 	switch (page_cache) {
X 	case 0:
-		page_cache = __get_free_page(GFP_USER);
+		page_cache = page_cache_alloc();
X 		if (!page_cache)
X 			break;
X 	default:
@@ -286,12 +280,12 @@
X 			/*
X 			 * Ok, add the new page to the hash-queues...
X 			 */
-			page = mem_map + MAP_NR(page_cache);
+			page = page_cache_entry(page_cache);
X 			add_to_page_cache(page, inode, offset, hash);
X 			inode->i_op->readpage(file, page);
X 			page_cache = 0;
X 		}
-		release_page(page);
+		page_cache_release(page);
X 	}
X 	return page_cache;
X }
@@ -413,7 +407,7 @@
X  * performances.
X  * Reasonable means, in this context, not too large but not too small.
X  * The actual maximum value is:
- *	MAX_READAHEAD + PAGE_SIZE = 76k is CONFIG_READA_SMALL is undefined
+ *	MAX_READAHEAD + PAGE_CACHE_SIZE = 76k is CONFIG_READA_SMALL is undefined
X  *      and 32K if defined (4K page size assumed).
X  *
X  * Asynchronous read-ahead benefits:
@@ -440,7 +434,7 @@
X  *   ONE seems to be the only reasonable value.
X  * - The total memory pool usage for the file access stream.
X  *   This maximum memory usage is implicitly 2 IO read chunks:
- *   2*(MAX_READAHEAD + PAGE_SIZE) = 156K if CONFIG_READA_SMALL is undefined,
+ *   2*(MAX_READAHEAD + PAGE_CACHE_SIZE) = 156K if CONFIG_READA_SMALL is undefined,
X  *   64k if defined (4K page size assumed).
X  */
X 
@@ -459,7 +453,7 @@
X 	unsigned long raend;
X 	int max_readahead = get_max_readahead(inode);
X 
-	raend = filp->f_raend & PAGE_MASK;
+	raend = filp->f_raend & PAGE_CACHE_MASK;
X 	max_ahead = 0;
X 
X /*
@@ -476,7 +470,7 @@
X 			if (raend < inode->i_size)
X 				max_ahead = filp->f_ramax;
X 			filp->f_rawin = 0;
-			filp->f_ralen = PAGE_SIZE;
+			filp->f_ralen = PAGE_CACHE_SIZE;
X 			if (!max_ahead) {
X 				filp->f_raend  = ppos + filp->f_ralen;
X 				filp->f_rawin += filp->f_ralen;
@@ -491,17 +485,17 @@
X  *   it is the moment to try to read ahead asynchronously.
X  * We will later force unplug device in order to force asynchronous read IO.
X  */
-	else if (reada_ok && filp->f_ramax && raend >= PAGE_SIZE &&
+	else if (reada_ok && filp->f_ramax && raend >= PAGE_CACHE_SIZE &&
X 	         ppos <= raend && ppos + filp->f_ralen >= raend) {
X /*
X  * Add ONE page to max_ahead in order to try to have about the same IO max size
- * as synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_SIZE.
+ * as synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_CACHE_SIZE.
X  * Compute the position of the last page we have tried to read in order to 
X  * begin to read ahead just at the next page.
X  */
-		raend -= PAGE_SIZE;
+		raend -= PAGE_CACHE_SIZE;
X 		if (raend < inode->i_size)
-			max_ahead = filp->f_ramax + PAGE_SIZE;
+			max_ahead = filp->f_ramax + PAGE_CACHE_SIZE;
X 
X 		if (max_ahead) {
X 			filp->f_rawin = filp->f_ralen;
@@ -516,7 +510,7 @@
X  */
X 	ahead = 0;
X 	while (ahead < max_ahead) {
-		ahead += PAGE_SIZE;
+		ahead += PAGE_CACHE_SIZE;
X 		page_cache = try_to_read_ahead(filp, raend + ahead,
X 						page_cache);
X 	}
@@ -538,7 +532,7 @@
X 
X 		filp->f_ralen += ahead;
X 		filp->f_rawin += filp->f_ralen;
-		filp->f_raend = raend + ahead + PAGE_SIZE;
+		filp->f_raend = raend + ahead + PAGE_CACHE_SIZE;
X 
X 		filp->f_ramax += filp->f_ramax;
X 
@@ -590,7 +584,7 @@
X 	page_cache = 0;
X 
X 	pos = *ppos;
-	pgpos = pos & PAGE_MASK;
+	pgpos = pos & PAGE_CACHE_MASK;
X /*
X  * If the current position is outside the previous read-ahead window, 
X  * we reset the current read-ahead context and set read ahead max to zero
@@ -614,12 +608,12 @@
X  * Then, at least MIN_READAHEAD if read ahead is ok,
X  * and at most MAX_READAHEAD in all cases.
X  */
-	if (pos + desc->count <= (PAGE_SIZE >> 1)) {
+	if (pos + desc->count <= (PAGE_CACHE_SIZE >> 1)) {
X 		filp->f_ramax = 0;
X 	} else {
X 		unsigned long needed;
X 
-		needed = ((pos + desc->count) & PAGE_MASK) - pgpos;
+		needed = ((pos + desc->count) & PAGE_CACHE_MASK) - pgpos;
X 
X 		if (filp->f_ramax < needed)
X 			filp->f_ramax = needed;
@@ -639,8 +633,8 @@
X 		/*
X 		 * Try to find the data in the page cache..
X 		 */
-		hash = page_hash(inode, pos & PAGE_MASK);
-		page = __find_page(inode, pos & PAGE_MASK, *hash);
+		hash = page_hash(inode, pos & PAGE_CACHE_MASK);
+		page = __find_page(inode, pos & PAGE_CACHE_MASK, *hash);
X 		if (!page)
X 			goto no_cached_page;
X 
@@ -653,7 +647,7 @@
X  * the page has been rewritten.
X  */
X 		if (PageUptodate(page) || PageLocked(page))
-			page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_MASK, page, page_cache);
+			page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_CACHE_MASK, page, page_cache);
X 		else if (reada_ok && filp->f_ramax > MIN_READAHEAD)
X 				filp->f_ramax = MIN_READAHEAD;
X 
@@ -670,8 +664,8 @@
X 	{
X 		unsigned long offset, nr;
X 
-		offset = pos & ~PAGE_MASK;
-		nr = PAGE_SIZE - offset;
+		offset = pos & ~PAGE_CACHE_MASK;
+		nr = PAGE_CACHE_SIZE - offset;
X 		if (nr > inode->i_size - pos)
X 			nr = inode->i_size - pos;
X 
@@ -684,7 +678,7 @@
X 		 */
X 		nr = actor(desc, (const char *) (page_address(page) + offset), nr);
X 		pos += nr;
-		release_page(page);
+		page_cache_release(page);
X 		if (nr && desc->count)
X 			continue;
X 		break;
@@ -696,7 +690,7 @@
X 		 * page..
X 		 */
X 		if (!page_cache) {
-			page_cache = __get_free_page(GFP_USER);
+			page_cache = page_cache_alloc();
X 			/*
X 			 * That could have slept, so go around to the
X 			 * very beginning..
@@ -710,9 +704,9 @@
X 		/*
X 		 * Ok, add the new page to the hash-queues...
X 		 */
-		page = mem_map + MAP_NR(page_cache);
+		page = page_cache_entry(page_cache);
X 		page_cache = 0;
-		add_to_page_cache(page, inode, pos & PAGE_MASK, hash);
+		add_to_page_cache(page, inode, pos & PAGE_CACHE_MASK, hash);
X 
X 		/*
X 		 * Error handling is tricky. If we get a read error,
@@ -737,7 +731,7 @@
X 			if (!error)
X 				goto found_page;
X 			desc->error = error;
-			release_page(page);
+			page_cache_release(page);
X 			break;
X 		}
X 
@@ -756,7 +750,7 @@
X 				error = -EIO; /* Some unspecified error occurred.. */
X 			}
X 			desc->error = error;
-			release_page(page);
+			page_cache_release(page);
X 			break;
X 		}
X 	}
@@ -764,7 +758,7 @@
X 	*ppos = pos;
X 	filp->f_reada = 1;
X 	if (page_cache)
-		free_page(page_cache);
+		page_cache_free(page_cache);
X 	UPDATE_ATIME(inode);
X }
X 
@@ -962,7 +956,7 @@
X 	 * extra page -- better to overlap the allocation with the I/O.
X 	 */
X 	if (no_share && !new_page) {
-		new_page = __get_free_page(GFP_USER);
+		new_page = page_cache_alloc();
X 		if (!new_page)
X 			goto failure;
X 	}
@@ -984,7 +978,7 @@
X 		 * of any potential extra pages.
X 		 */
X 		if (new_page)
-			free_page(new_page);
+			page_cache_free(new_page);
X 
X 		flush_page_to_ram(old_page);
X 		return old_page;
@@ -995,7 +989,7 @@
X 	 */
X 	copy_page(new_page, old_page);
X 	flush_page_to_ram(new_page);
-	release_page(page);
+	page_cache_release(page);
X 	return new_page;
X 
X no_cached_page:
@@ -1003,14 +997,14 @@
X 	 * Try to read in an entire cluster at once.
X 	 */
X 	reada   = offset;
-	reada >>= PAGE_SHIFT + page_cluster;
-	reada <<= PAGE_SHIFT + page_cluster;
+	reada >>= PAGE_CACHE_SHIFT + page_cluster;
+	reada <<= PAGE_CACHE_SHIFT + page_cluster;
X 
-	for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_SIZE)
+	for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_CACHE_SIZE)
X 		new_page = try_to_read_ahead(file, reada, new_page);
X 
X 	if (!new_page)
-		new_page = __get_free_page(GFP_USER);
+		new_page = page_cache_alloc();
X 	if (!new_page)
X 		goto no_page;
X 
@@ -1027,7 +1021,7 @@
X 	/*
X 	 * Now, create a new page-cache page from the page we got
X 	 */
-	page = mem_map + MAP_NR(new_page);
+	page = page_cache_entry(new_page);
X 	new_page = 0;
X 	add_to_page_cache(page, inode, offset, hash);
X 
@@ -1061,9 +1055,9 @@
X 	 * mm layer so, possibly freeing the page cache page first.
X 	 */
X failure:
-	release_page(page);
+	page_cache_release(page);
X 	if (new_page)
-		free_page(new_page);
+		page_cache_free(new_page);
X no_page:
X 	return 0;
X }
@@ -1166,7 +1160,7 @@
X 		set_pte(ptep, pte_mkclean(pte));
X 		flush_tlb_page(vma, address);
X 		page = pte_page(pte);
-		atomic_inc(&mem_map[MAP_NR(page)].count);
+		atomic_inc(&page_cache_entry(page)->count);
X 	} else {
X 		if (pte_none(pte))
X 			return 0;
@@ -1179,12 +1173,12 @@
X 		}
X 		page = pte_page(pte);
X 		if (!pte_dirty(pte) || flags == MS_INVALIDATE) {
-			free_page(page);
+			page_cache_free(page);
X 			return 0;
X 		}
X 	}
X 	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page, 1);
-	free_page(page);
+	page_cache_free(page);
X 	return error;
X }
X 
@@ -1492,9 +1486,9 @@
X 		 * Try to find the page in the cache. If it isn't there,
X 		 * allocate a free page.
X 		 */
-		offset = (pos & ~PAGE_MASK);
-		pgpos = pos & PAGE_MASK;
-		bytes = PAGE_SIZE - offset;
+		offset = (pos & ~PAGE_CACHE_MASK);
+		pgpos = pos & PAGE_CACHE_MASK;
+		bytes = PAGE_CACHE_SIZE - offset;
X 		if (bytes > count)
X 			bytes = count;
X 
@@ -1502,13 +1496,13 @@
X 		page = __find_page(inode, pgpos, *hash);
X 		if (!page) {
X 			if (!page_cache) {
-				page_cache = __get_free_page(GFP_USER);
+				page_cache = page_cache_alloc();
X 				if (page_cache)
X 					continue;
X 				status = -ENOMEM;
X 				break;
X 			}
-			page = mem_map + MAP_NR(page_cache);
+			page = page_cache_entry(page_cache);
X 			add_to_page_cache(page, inode, pgpos, hash);
X 			page_cache = 0;
X 		}
@@ -1530,7 +1524,7 @@
X 		/* Mark it unlocked again and drop the page.. */
X 		clear_bit(PG_locked, &page->flags);
X 		wake_up(&page->wait);
-		__free_page(page);
+		page_cache_release(page);
X 
X 		if (status < 0)
X 			break;
@@ -1545,7 +1539,7 @@
X 		inode->i_size = pos;
X 
X 	if (page_cache)
-		free_page(page_cache);
+		page_cache_free(page_cache);
X out:
X 	return written ? written : status;
X }
@@ -1573,10 +1567,11 @@
X 	if (!page) {
X 		if (!new)
X 			goto out;
-		page_cache = get_free_page(GFP_USER);
+		page_cache = page_cache_alloc();
X 		if (!page_cache)
X 			goto out;
-		page = mem_map + MAP_NR(page_cache);
+		clear_page(page_cache);
+		page = page_cache_entry(page_cache);
X 		add_to_page_cache(page, inode, offset, hash);
X 	}
X 	if (atomic_read(&page->count) != 2)
@@ -1596,7 +1591,7 @@
X  */
X void put_cached_page(unsigned long addr)
X {
-	struct page * page = mem_map + MAP_NR(addr);
+	struct page * page = page_cache_entry(addr);
X 
X 	if (!test_bit(PG_locked, &page->flags))
X 		printk("put_cached_page: page not locked!\n");
@@ -1605,7 +1600,7 @@
X 			atomic_read(&page->count));
X 	clear_bit(PG_locked, &page->flags);
X 	wake_up(&page->wait);
-	__free_page(page);
+	page_cache_release(page);
X }
X 
X 
@@ -1637,7 +1632,7 @@
X {
X 	struct pio_request *p;
X 
-	atomic_inc(&mem_map[MAP_NR(page)].count);
+	atomic_inc(&page_cache_entry(page)->count);
X 
X 	/* 
X 	 * We need to allocate without causing any recursive IO in the
@@ -1726,7 +1721,7 @@
X 				      (const char *) p->page, p->offset);
X 			up(&inode->i_sem);
X 			fput(p->file);
-			free_page(p->page);
+			page_cache_free(p->page);
X 			kmem_cache_free(pio_request_cache, p);
X 		}
X 	}
diff -u --recursive --new-file v2.2.7/linux/mm/mmap.c linux/mm/mmap.c
--- v2.2.7/linux/mm/mmap.c	Fri Apr 16 14:47:31 1999
+++ linux/mm/mmap.c	Tue May  4 15:44:38 1999
@@ -176,6 +176,9 @@
X 	struct vm_area_struct * vma;
X 	int error;
X 
+	if (file && (!file->f_op || !file->f_op->mmap))
+		return -ENODEV;
+
X 	if ((len = PAGE_ALIGN(len)) == 0)
X 		return addr;
X 
@@ -244,9 +247,6 @@
X 	 * specific mapper. the address has already been validated, but
X 	 * not unmapped, but the maps are removed from the list.
X 	 */
-	if (file && (!file->f_op || !file->f_op->mmap))
-		return -ENODEV;
-
X 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
X 	if (!vma)
X 		return -ENOMEM;
diff -u --recursive --new-file v2.2.7/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.2.7/linux/mm/page_alloc.c	Wed Apr 28 11:37:32 1999
+++ linux/mm/page_alloc.c	Thu May  6 14:32:06 1999
@@ -419,12 +419,12 @@
X 		return;
X 	}
X 
-	/* The page is unshared, and we want write access.  In this
-	   case, it is safe to tear down the swap cache and give the
-	   page over entirely to this process. */
-
-	if (PageSwapCache(page_map))
-		delete_from_swap_cache(page_map);
+	/*
+	 * The page is unshared and we're going to dirty it - so tear
+	 * down the swap cache and give exclusive access to the page to
+	 * this process.
+	 */
+	delete_from_swap_cache(page_map);
X 	set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
X   	return;
X }
diff -u --recursive --new-file v2.2.7/linux/net/TUNABLE linux/net/TUNABLE
--- v2.2.7/linux/net/TUNABLE	Thu Jan  7 15:11:41 1999
+++ linux/net/TUNABLE	Mon May 10 13:01:21 1999
@@ -5,10 +5,7 @@
X 
X Item			Description
X ----------------------------------------------------------------------------
-MAX_SOCKETS		Tunable on boot, maximum sockets we will allocate
-NUM_PROTO		Maximum loadable address family, will need recompile
X MAX_LINKS		Maximum number of netlink minor devices. (1-32)
-MAX_QBYTES		Size of a netlink device queue (tunable)
X RIF_TABLE_SIZE		Token ring RIF cache size (tunable)
X AARP_HASH_SIZE		Size of Appletalk hash table (tunable)
X AX25_DEF_T1		AX.25 parameters. These are all tunable via
@@ -34,18 +31,9 @@
X MAX_HEADER		Largest physical header (tunable)
X MAX_ADDR_LEN		Largest physical address (tunable)
X SOCK_ARRAY_SIZE		IP socket array hash size (tunable)
-ARP_RES_TIME		Time we try to resolve (tunable)
-ARP_DEAD_RES_TIME	Time the entry stays dead (tunable)
-ARP_MAX_TRIES		Maximum tries (tunable)
-ARP_TIMEOUT		Timeout on an ARP (tunable)
-ARP_CHECK_INTERVAL	Check interval to refresh an arp (tunable)
-ARP_CONFIRM_INTERVAL	Confirm poll time (tunable)
-ARP_TABLE_SIZE		Hash table size for ARP (tunable)
X IP_MAX_MEMBERSHIPS	Largest number of groups per socket (BSD style) (tunable)
X 16			Hard coded constant for amount of room allowed for
X 			cache align and faster forwarding (tunable)
-IPFRAG_HIGH_THRESH	Limit on fragments, we free fragments until we reach
-IPFRAG_LOW_THRESH	which provides some breathing space. (tunable)
X IP_FRAG_TIME		Time we hold a fragment for. (tunable)
X PORT_MASQ_BEGIN		First port reserved for masquerade (tunable)
X PORT_MASQ_END		Last port used for masquerade	(tunable)
diff -u --recursive --new-file v2.2.7/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.2.7/linux/net/core/iovec.c	Mon Sep 28 10:51:36 1998
+++ linux/net/core/iovec.c	Mon May 10 09:55:25 1999
@@ -59,8 +59,15 @@
X 		goto out;
X 	m->msg_iov=iov;
X 
-	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++)
+	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) {
X 		err += iov[ct].iov_len;
+		/* Goal is not to verify user data, but to prevent returning
+		   negative value, which is interpreted as errno.
+		   Overflow is still possible, but it is harmless.
+		 */
+		if (err < 0)
+			return -EMSGSIZE;
+	}
X out:
X 	return err;
X }
diff -u --recursive --new-file v2.2.7/linux/net/core/sock.c linux/net/core/sock.c
--- v2.2.7/linux/net/core/sock.c	Mon Mar 29 11:09:12 1999
+++ linux/net/core/sock.c	Mon May 10 09:55:25 1999
@@ -7,7 +7,7 @@
X  *		handler for protocols to use and generic option handler.
X  *
X  *
- * Version:	$Id: sock.c,v 1.79 1999/03/28 10:18:25 davem Exp $
+ * Version:	$Id: sock.c,v 1.80 1999/05/08 03:04:34 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -944,7 +944,7 @@
X 			 */
X 			if (current->pgrp != -arg &&
X 				current->pid != arg &&
-				!capable(CAP_NET_ADMIN)) return(-EPERM);
+				!capable(CAP_KILL)) return(-EPERM);
X 			sk->proc = arg;
X 			return(0);
X 		case F_GETOWN:
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.2.7/linux/net/ipv4/devinet.c	Mon Mar 29 11:09:12 1999
+++ linux/net/ipv4/devinet.c	Mon May 10 09:55:25 1999
@@ -1,7 +1,7 @@
X /*
X  *	NET3	IP device support routines.
X  *
- *	Version: $Id: devinet.c,v 1.27 1999/03/25 10:04:06 davem Exp $
+ *	Version: $Id: devinet.c,v 1.28 1999/05/08 20:00:16 davem Exp $
X  *
X  *		This program is free software; you can redistribute it and/or
X  *		modify it under the terms of the GNU General Public License
@@ -712,6 +712,7 @@
X 				ifa->ifa_mask = inet_make_mask(8);
X 				ifa->ifa_dev = in_dev;
X 				ifa->ifa_scope = RT_SCOPE_HOST;
+				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
X 				inet_insert_ifa(in_dev, ifa);
X 			}
X 		}
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.2.7/linux/net/ipv4/route.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/route.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
X  *
X  *		ROUTE - implementation of the IP router.
X  *
- * Version:	$Id: route.c,v 1.66 1999/04/22 10:07:35 davem Exp $
+ * Version:	$Id: route.c,v 1.67 1999/05/08 20:00:20 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -1492,13 +1492,16 @@
X 			return -ENODEV;	/* Wrong error code */
X 
X 		if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) {
-			key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
+			if (!key.src)
+				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
X 			goto make_route;
X 		}
-		if (MULTICAST(daddr))
-			key.src = inet_select_addr(dev_out, 0, key.scope);
-		else if (!daddr)
-			key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+		if (!key.src) {
+			if (MULTICAST(daddr))
+				key.src = inet_select_addr(dev_out, 0, key.scope);
+			else if (!daddr)
+				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+		}
X 	}
X 
X 	if (!key.dst) {
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.2.7/linux/net/ipv4/tcp_input.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_input.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
X  *
X  *		Implementation of the Transmission Control Protocol(TCP).
X  *
- * Version:	$Id: tcp_input.c,v 1.163 1999/04/28 16:08:05 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164 1999/05/08 21:09:52 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -497,8 +497,7 @@
X 		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
X 			tp->dup_acks++;
X 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-                                tp->snd_ssthresh =
-					max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
+                                tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
X                                 tp->snd_cwnd = (tp->snd_ssthresh + 3);
X 				tp->high_seq = tp->snd_nxt;
X 				if(!tp->fackets_out)
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.2.7/linux/net/ipv4/tcp_ipv4.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_ipv4.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
X  *
X  *		Implementation of the Transmission Control Protocol(TCP).
X  *
- * Version:	$Id: tcp_ipv4.c,v 1.174 1999/04/28 16:08:19 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175 1999/05/08 21:09:54 davem Exp $
X  *
X  *		IPv4 specific functions
X  *
@@ -819,7 +819,7 @@
X 	switch (type) {
X 	case ICMP_SOURCE_QUENCH:
X #ifndef OLD_SOURCE_QUENCH /* This is deprecated */
-		tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
X 		tp->snd_cwnd = tp->snd_ssthresh;
X 		tp->snd_cwnd_cnt = 0;
X 		tp->high_seq = tp->snd_nxt;
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.2.7/linux/net/ipv4/tcp_output.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_output.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
X  *
X  *		Implementation of the Transmission Control Protocol(TCP).
X  *
- * Version:	$Id: tcp_output.c,v 1.107 1999/04/28 16:08:12 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.108 1999/05/08 21:48:59 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -521,24 +521,39 @@
X void tcp_simple_retransmit(struct sock *sk)
X {
X 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct sk_buff *skb; 
-	unsigned int mss = tcp_current_mss(sk); 
+	struct sk_buff *skb, *old_next_skb;
+	unsigned int mss = tcp_current_mss(sk);
X 
X  	/* Don't muck with the congestion window here. */
X  	tp->dup_acks = 0;
X  	tp->high_seq = tp->snd_nxt;
- 	tp->retrans_head = NULL; 
+ 	tp->retrans_head = NULL;
X 
X  	/* Input control flow will see that this was retransmitted
X 	 * and not use it for RTT calculation in the absence of
X 	 * the timestamp option.
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
fi
echo 'End of  part 32'
echo 'File patch-2.2.8 is continued in part 33'
echo 33 > _shar_seq_.tmp
#!/bin/sh
# this is part 33 of a 33 - part archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file patch-2.2.8 continued
if test ! -r _shar_seq_.tmp; then
        echo 'Please unpack part 1 first!'
        exit 1
fi
(read Scheck
if test "$Scheck" != 33; then
        echo Please unpack part "$Scheck" next!
        exit 1
 else
        exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping patch-2.2.8'
else
echo 'x - continuing with patch-2.2.8'
sed 's/^X//' << 'SHAR_EOF' >> 'patch-2.2.8' &&
X 	 */
-	for (skb = skb_peek(&sk->write_queue);
+	for (old_next_skb = skb = skb_peek(&sk->write_queue);
X 	     ((skb != tp->send_head) &&
X 	      (skb != (struct sk_buff *)&sk->write_queue));
-	     skb = skb->next) 
-		if (skb->len > mss)
-			tcp_retransmit_skb(sk, skb); 
+	     skb = skb->next) {
+		int resend_skb = 0;
+
+		/* Our goal is to push out the packets which we
+		 * sent already, but are being chopped up now to
+		 * account for the PMTU information we have.
+		 *
+		 * As we resend the queue, packets are fragmented
+		 * into two pieces, and when we try to send the
+		 * second piece it may be collapsed together with
+		 * a subsequent packet, and so on.  -DaveM
+		 */
+		if (old_next_skb != skb || skb->len > mss)
+			resend_skb = 1;
+		old_next_skb = skb->next;
+		if (resend_skb != 0)
+			tcp_retransmit_skb(sk, skb);
+	}
X }
X 
X static __inline__ void update_retrans_head(struct sock *sk)
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.2.7/linux/net/ipv4/tcp_timer.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_timer.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
X  *
X  *		Implementation of the Transmission Control Protocol(TCP).
X  *
- * Version:	$Id: tcp_timer.c,v 1.60 1999/04/28 16:08:21 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.62 1999/05/08 21:09:55 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -317,48 +317,47 @@
X void tcp_tw_schedule(struct tcp_tw_bucket *tw)
X {
X 	int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+	struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot];
+
+	if((tw->next_death = *tpp) != NULL)
+		(*tpp)->pprev_death = &tw->next_death;
+	*tpp = tw;
+	tw->pprev_death = tpp;
X 
X 	tw->death_slot = slot;
-	tw->next_death = tcp_tw_death_row[slot];
-	tcp_tw_death_row[slot] = tw;
+
X 	tcp_inc_slow_timer(TCP_SLT_TWKILL);
X }
X 
X /* Happens rarely if at all, no care about scalability here. */
X void tcp_tw_reschedule(struct tcp_tw_bucket *tw)
X {
-	struct tcp_tw_bucket *walk;
-	int slot = tw->death_slot;
+	struct tcp_tw_bucket **tpp;
+	int slot;
+
+	if(tw->next_death)
+		tw->next_death->pprev_death = tw->pprev_death;
+	*tw->pprev_death = tw->next_death;
+	tw->pprev_death = NULL;
X 
-	walk = tcp_tw_death_row[slot];
-	if(walk == tw) {
-		tcp_tw_death_row[slot] = tw->next_death;
-	} else {
-		while(walk->next_death != tw)
-			walk = walk->next_death;
-		walk->next_death = tw->next_death;
-	}
X 	slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+	tpp = &tcp_tw_death_row[slot];
+	if((tw->next_death = *tpp) != NULL)
+		(*tpp)->pprev_death = &tw->next_death;
+	*tpp = tw;
+	tw->pprev_death = tpp;
+
X 	tw->death_slot = slot;
-	tw->next_death = tcp_tw_death_row[slot];
-	tcp_tw_death_row[slot] = tw;
X 	/* Timer was incremented when we first entered the table. */
X }
X 
X /* This is for handling early-kills of TIME_WAIT sockets. */
X void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
X {
-	struct tcp_tw_bucket *walk;
-	int slot = tw->death_slot;
-
-	walk = tcp_tw_death_row[slot];
-	if(walk == tw) {
-		tcp_tw_death_row[slot] = tw->next_death;
-	} else {
-		while(walk->next_death != tw)
-			walk = walk->next_death;
-		walk->next_death = tw->next_death;
-	}
+	if(tw->next_death)
+		tw->next_death->pprev_death = tw->pprev_death;
+	*tw->pprev_death = tw->next_death;
+	tw->pprev_death = NULL;
X 	tcp_dec_slow_timer(TCP_SLT_TWKILL);
X }
X 
@@ -478,7 +477,7 @@
X 		 * means it must be an accurate representation of our current
X 		 * sending rate _and_ the snd_wnd.
X 		 */
-		tp->snd_ssthresh = max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
X 		tp->snd_cwnd_cnt = 0;
X 		tp->snd_cwnd = 1;
X 	}
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.2.7/linux/net/ipv4/udp.c	Tue Mar 23 14:35:48 1999
+++ linux/net/ipv4/udp.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
X  *
X  *		The User Datagram Protocol (UDP).
X  *
- * Version:	$Id: udp.c,v 1.65 1999/03/21 05:22:49 davem Exp $
+ * Version:	$Id: udp.c,v 1.66 1999/05/08 20:00:25 davem Exp $
X  *
X  * Authors:	Ross Biro, <bi...@leland.Stanford.Edu>
X  *		Fred N. van Kempen, <wal...@uWalt.NL.Mugnet.ORG>
@@ -955,7 +955,7 @@
X 	 * Error for blocking case is chosen to masquerade
X    	 * as some normal condition.
X 	 */
-	return (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;	
+	return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;	
X #endif
X }
X 
diff -u --recursive --new-file v2.2.7/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.2.7/linux/net/ipv6/udp.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv6/udp.c	Mon May 10 09:55:25 1999
@@ -7,7 +7,7 @@
X  *
X  *	Based on linux/ipv4/udp.c
X  *
- *	$Id: udp.c,v 1.39 1999/04/22 10:07:47 davem Exp $
+ *	$Id: udp.c,v 1.40 1999/05/08 20:00:32 davem Exp $
X  *
X  *	This program is free software; you can redistribute it and/or
X  *      modify it under the terms of the GNU General Public License
@@ -381,7 +381,7 @@
X 			/* Error for blocking case is chosen to masquerade
X 			   as some normal condition.
X 			 */
-			err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+			err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
X 			udp_stats_in6.UdpInErrors++;
X 			goto out_free;
X 		}
@@ -398,7 +398,7 @@
X 			/* Error for blocking case is chosen to masquerade
X 			   as some normal condition.
X 			 */
-			err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+			err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
X 			udp_stats_in6.UdpInErrors++;
X 			goto out_free;
X 		}
diff -u --recursive --new-file v2.2.7/linux/net/irda/ircomm/ircomm_common.c linux/net/irda/ircomm/ircomm_common.c
--- v2.2.7/linux/net/irda/ircomm/ircomm_common.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/ircomm/ircomm_common.c	Thu May  6 16:40:53 1999
@@ -147,13 +147,7 @@
X };
X 
X #ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry proc_irda;
-struct proc_dir_entry proc_ircomm = {
-	0, 6, "ircomm",
-        S_IFREG | S_IRUGO, 1, 0, 0,
-        0, NULL,
-        &ircomm_proc_read,
-};
+extern struct proc_dir_entry *proc_irda;
X #endif
X 
X static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
@@ -229,7 +223,7 @@
X 	 */
X 
X #ifdef CONFIG_PROC_FS
-	proc_register( &proc_irda, &proc_ircomm);
+	create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
X #endif /* CONFIG_PROC_FS */
X 
X 
@@ -267,7 +261,7 @@
X 	}
X 
X #ifdef CONFIG_PROC_FS
-	proc_unregister( &proc_irda, proc_ircomm.low_ino);
+	remove_proc_entry("ircomm", proc_irda);
X #endif /* CONFIG_PROC_FS */
X }
X #endif /* MODULE */
diff -u --recursive --new-file v2.2.7/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.2.7/linux/net/irda/irlan/irlan_common.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_common.c	Thu May  6 16:40:53 1999
@@ -99,15 +99,8 @@
X static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
X 			   int unused);
X 
-extern struct proc_dir_entry proc_irda;
-
-struct proc_dir_entry proc_irlan = {
-	0, 5, "irlan",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL,
-	&irlan_proc_read,
-};
-#endif /* CONFIG_PROC_FS */
+extern struct proc_dir_entry *proc_irda;
+#endif
X 
X void irlan_watchdog_timer_expired(unsigned long data)
X {
@@ -188,7 +181,7 @@
X 		return -ENOMEM;
X 	}
X #ifdef CONFIG_PROC_FS
-	proc_register(&proc_irda, &proc_irlan);
+	create_proc_entry("irlan", 0, proc_irda)->get_info = irlan_proc_read;
X #endif /* CONFIG_PROC_FS */
X 
X 	DEBUG(4, __FUNCTION__ "()\n");
@@ -224,7 +217,7 @@
X 	irlmp_unregister_service(skey);
X 
X #ifdef CONFIG_PROC_FS
-	proc_unregister(&proc_irda, proc_irlan.low_ino);
+	remove_proc_entry("irlan", proc_irda);
X #endif /* CONFIG_PROC_FS */
X 	/*
X 	 *  Delete hashbin and close all irlan client instances in it
diff -u --recursive --new-file v2.2.7/linux/net/irda/irlpt/irlpt_cli.c linux/net/irda/irlpt/irlpt_cli.c
--- v2.2.7/linux/net/irda/irlpt/irlpt_cli.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlpt/irlpt_cli.c	Thu May  6 16:40:53 1999
@@ -157,14 +157,7 @@
X 	return len;
X }
X 
-struct proc_dir_entry proc_irlpt_client = {
-	0, 12, "irlpt_client",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlpt_client_proc_read /* get_info */,
-};
-
-extern struct proc_dir_entry proc_irda;
+extern struct proc_dir_entry *proc_irda;
X 
X #endif /* CONFIG_PROC_FS */
X 
@@ -193,7 +186,8 @@
X 				     NULL);
X 
X #ifdef CONFIG_PROC_FS
-	proc_register( &proc_irda, &proc_irlpt_client);
+	create_proc_entry("irlpt_client", 0, proc_irda)->get_info
+			= irlpt_client_proc_read;
X #endif /* CONFIG_PROC_FS */
X 
X 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
@@ -219,7 +213,7 @@
X 	hashbin_delete( irlpt_clients, (FREE_FUNC) irlpt_client_close);
X 
X #ifdef CONFIG_PROC_FS
-	proc_unregister( &proc_irda, proc_irlpt_client.low_ino);
+	remove_proc_entry("irlpt_client", proc_irda);
X #endif
X 
X 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
diff -u --recursive --new-file v2.2.7/linux/net/irda/irlpt/irlpt_srvr.c linux/net/irda/irlpt/irlpt_srvr.c
--- v2.2.7/linux/net/irda/irlpt/irlpt_srvr.c	Fri Apr 16 14:47:31 1999
+++ linux/net/irda/irlpt/irlpt_srvr.c	Thu May  6 16:40:53 1999
@@ -160,14 +160,7 @@
X 	return len;
X }
X 
-extern struct proc_dir_entry proc_irda;
-
-struct proc_dir_entry proc_irlpt_server = {
-	0, 12, "irlpt_server",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlpt_server_proc_read /* get_info */,
-};
+extern struct proc_dir_entry *proc_irda;
X 
X #endif /* CONFIG_PROC_FS */
X 
@@ -215,7 +208,8 @@
X 	register_irlpt_server();
X 
X #ifdef CONFIG_PROC_FS
-	proc_register( &proc_irda, &proc_irlpt_server);
+	create_proc_entry("irlpt_server", 0, proc_irda)->get_info
+		= irlpt_server_proc_read;
X #endif /* CONFIG_PROC_FS */
X 
X 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
@@ -248,7 +242,7 @@
X 	kfree(irlpt_server);
X 
X #ifdef CONFIG_PROC_FS
-	proc_unregister( &proc_irda, proc_irlpt_server.low_ino);
+	remove_proc_entry("irlpt_server", proc_irda);
X #endif
X 
X 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
diff -u --recursive --new-file v2.2.7/linux/net/irda/irproc.c linux/net/irda/irproc.c
--- v2.2.7/linux/net/irda/irproc.c	Fri Apr 16 14:47:31 1999
+++ linux/net/irda/irproc.c	Mon May 10 13:01:21 1999
@@ -32,11 +32,6 @@
X #include <net/irda/irlap.h>
X #include <net/irda/irlmp.h>
X 
-static int proc_irda_lookup(struct inode * dir, struct dentry *dentry);
-
-static int proc_irda_readdir(struct file *filp, void *dirent, 
- 			     filldir_t filldir);
-
X extern int irda_device_proc_read(char *buf, char **start, off_t offset, 
X 				 int len, int unused);
X extern int irlap_proc_read(char *buf, char **start, off_t offset, int len, 
@@ -50,9 +45,6 @@
X extern int discovery_proc_read(char *buf, char **start, off_t offset, int len, 
X 			       int unused);
X 
-static int proc_discovery_read(char *buf, char **start, off_t offset, int len,
-			       int unused);
-
X enum irda_directory_inos {
X 	PROC_IRDA_LAP = 1,
X 	PROC_IRDA_LMP,
@@ -63,121 +55,26 @@
X 	PROC_IRDA_IRIAS
X };
X 
-static struct file_operations proc_irda_dir_operations = {
-        NULL,                   /* lseek - default */
-        NULL,                   /* read - bad */
-        NULL,                   /* write - bad */
-        proc_irda_readdir,      /* readdir */
-        NULL,                   /* select - default */
-        NULL,                   /* ioctl - default */
-        NULL,                   /* mmap */
-        NULL,                   /* no special open code */
-        NULL,                   /* no special release code */
-        NULL                    /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_irda_dir_inode_operations = {
-        &proc_irda_dir_operations,   /* default net directory file-ops */
-        NULL,                   /* create */
-	proc_irda_lookup, 
-        NULL,                   /* link */
-        NULL,                   /* unlink */
-        NULL,                   /* symlink */
-        NULL,                   /* mkdir */
-        NULL,                   /* rmdir */
-        NULL,                   /* mknod */
-        NULL,                   /* rename */ 
-        NULL,                   /* readlink */
-        NULL,                   /* follow_link */
-        NULL,                   /* readpage */
-        NULL,                   /* writepage */
-        NULL,                   /* bmap */
-        NULL,                   /* truncate */   
-        NULL                    /* permission */
+struct irda_entry {
+	char *name;
+	int (*fn)(char*,char**,off_t,int,int);
X };
X 
-struct proc_dir_entry proc_irda = {
-	0, 4, "irda",
-        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
-        0, &proc_irda_dir_inode_operations,
-        NULL, NULL,
-        NULL,
-        NULL, NULL
-};
+struct proc_dir_entry *proc_irda;
X 
+static struct irda_entry dir[] = {
X #if 0 
-struct proc_dir_entry proc_lpt = {
-	0, 3, "lpt",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlpt_proc_read /* get_info */,
-};
+	{"lpt", irlpt_proc_read},
X #endif
-
-struct proc_dir_entry proc_discovery = {
-	0, 9, "discovery",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&discovery_proc_read /* get_info */,
+	{"discovery",	discovery_proc_read},
+	{"irda_device",	irda_device_proc_read},
+	{"irttp",	irttp_proc_read},
+	{"irlmp",	irlmp_proc_read},
+	{"irlap",	irlap_proc_read},
+	{"irias",	irias_proc_read},
X };
X 
-struct proc_dir_entry proc_irda_device = {
-	0, 11, "irda_device",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL,
-	&irda_device_proc_read,
-};
-
-struct proc_dir_entry proc_ttp = {
-	0, 5, "irttp",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irttp_proc_read /* get_info */,
-};
-
-struct proc_dir_entry proc_lmp = {
-	0, 5, "irlmp",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlmp_proc_read /* get_info */,
-};
-
-struct proc_dir_entry proc_lap = {
-	0, 5, "irlap",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlap_proc_read /* get_info */,
-};
-
-struct proc_dir_entry proc_ias = {
-	0, 5, "irias",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irias_proc_read /* get_info */,
-};
-
-/*
- * Function proc_delete_dentry (dentry)
- *
- *    Copy of proc/root.c because this function is invisible to the irda
- *    module
- * 
- */
-static void proc_delete_dentry(struct dentry * dentry)
-{
-	d_drop(dentry);
-}
-
-static struct dentry_operations proc_dentry_operations =
-{
-	NULL,			/* revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	proc_delete_dentry	/* d_delete(struct dentry *) */
-};
+#define IRDA_ENTRIES_NUM (sizeof(dir)/sizeof(dir[0]))
X 
X /*
X  * Function irda_proc_register (void)
@@ -186,16 +83,13 @@
X  *
X  */
X void irda_proc_register(void) {
-	proc_net_register(&proc_irda);
+	int i;
+	proc_irda = create_proc_entry("net/irda", S_IFDIR, NULL);
X #ifdef MODULE
-	proc_irda.fill_inode = &irda_proc_modcount;
+	proc_irda->fill_inode = &irda_proc_modcount;
X #endif /* MODULE */
-	proc_register(&proc_irda, &proc_lap);
-	proc_register(&proc_irda, &proc_lmp);
-	proc_register(&proc_irda, &proc_ttp);
-	proc_register(&proc_irda, &proc_ias);
- 	proc_register(&proc_irda, &proc_irda_device); 
-	proc_register(&proc_irda, &proc_discovery);
+	for (i=0;i<IRDA_ENTRIES_NUM;i++)
+		create_proc_entry(dir[i].name,0,proc_irda)->get_info=dir[i].fn;
X }
X 
X /*
@@ -205,116 +99,8 @@
X  *
X  */
X void irda_proc_unregister(void) {
-	proc_unregister(&proc_irda, proc_discovery.low_ino);
- 	proc_unregister(&proc_irda, proc_irda_device.low_ino);
-	proc_unregister(&proc_irda, proc_ias.low_ino);
-	proc_unregister(&proc_irda, proc_ttp.low_ino);
-	proc_unregister(&proc_irda, proc_lmp.low_ino);
-	proc_unregister(&proc_irda, proc_lap.low_ino);
-	proc_unregister(proc_net, proc_irda.low_ino);
-}
-
-/*
- * Function proc_irda_lookup (dir, dentry)
- *
- *    This is a copy of proc_lookup from the linux-2.2.x kernel
- *
- */
-int proc_irda_lookup(struct inode * dir, struct dentry *dentry)
-{
-	struct inode *inode;
-	struct proc_dir_entry * de;
-	int error;
-
-	error = -ENOTDIR;
-	if (!dir || !S_ISDIR(dir->i_mode))
-		goto out;
-
-	error = -ENOENT;
-	inode = NULL;
-	de = (struct proc_dir_entry *) dir->u.generic_ip;
-	if (de) {
-		for (de = de->subdir; de ; de = de->next) {
-			if (!de || !de->low_ino)
-				continue;
-			if (de->namelen != dentry->d_name.len)
-				continue;
-			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
-				int ino = de->low_ino | (dir->i_ino & ~(0xffff));
-				error = -EINVAL;
-				inode = proc_get_inode(dir->i_sb, ino, de);
-				break;
-			}
-		}
-	}
-
-	if (inode) {
-		dentry->d_op = &proc_dentry_operations;
-		d_add(dentry, inode);
-		error = 0;
-	}
-out:
-	return error;
-}
-
-/*
- * Function proc_irda_readdir (filp, dirent, filldir)
- *
- *    This is a copy from linux/fs/proc because the function is invisible
- *    to the irda module
- * 
- */
-static int proc_irda_readdir(struct file *filp, void *dirent, 
-			     filldir_t filldir)
-{
-	struct proc_dir_entry * de;
-	unsigned int ino;
X 	int i;
-	
-	struct inode *inode = filp->f_dentry->d_inode;
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
-	ino = inode->i_ino;
-	de = (struct proc_dir_entry *) inode->u.generic_ip;
-	if (!de)
-		return -EINVAL;
-	i = filp->f_pos;
-	switch (i) {
-	case 0:
-		if (filldir(dirent, ".", 1, i, ino) < 0)
-			return 0;
-		i++;
-		filp->f_pos++;
-		/* fall through */
-	case 1:
-		if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
-			return 0;
-		i++;
-		filp->f_pos++;
-		/* fall through */
-	default:
-		ino &= ~0xffff;
-		de = de->subdir;
-		i -= 2;
-		for (;;) {
-			if (!de)
-				return 1;
-			if (!i)
-				break;
-			de = de->next;
-			i--;
-		}
-		
-		do {
-			if (filldir(dirent, de->name, de->namelen, filp->f_pos,
-				    ino | de->low_ino) < 0)
-				return 0;
-			filp->f_pos++;
-			de = de->next;
-		} while (de);
-	}
-	return 1;
+	for (i=0;i<IRDA_ENTRIES_NUM;i++)
+		remove_proc_entry(dir[i].name, proc_irda);
+	remove_proc_entry("net/irda", NULL);
X }
-
-
-
diff -u --recursive --new-file v2.2.7/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.2.7/linux/net/sunrpc/sched.c	Wed Mar 10 15:29:53 1999
+++ linux/net/sunrpc/sched.c	Fri May  7 11:19:11 1999
@@ -174,6 +174,7 @@
X 		printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n");
X 		return;
X 	}
+	task->tk_flags |= RPC_TASK_RUNNING;
X 	if (RPC_IS_ASYNC(task)) {
X 		int status;
X 		status = rpc_add_wait_queue(&schedq, task);
@@ -186,7 +187,6 @@
X 	} else {
X 		wake_up(&task->tk_wait);
X 	}
-	task->tk_flags |= RPC_TASK_RUNNING;
X }
X 
X 
@@ -447,7 +447,10 @@
X 							task->tk_pid);
X 			if (current->pid == rpciod_pid)
X 				printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
-			sleep_on(&task->tk_wait);
+
+			sti();
+			__wait_event(task->tk_wait, RPC_IS_RUNNING(task));
+			cli();
X 
X 			/*
X 			 * When the task received a signal, remove from
diff -u --recursive --new-file v2.2.7/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.2.7/linux/net/sunrpc/svcsock.c	Tue Mar 23 14:35:48 1999
+++ linux/net/sunrpc/svcsock.c	Tue May  4 10:29:07 1999
@@ -249,7 +249,8 @@
X 	msg.msg_namelen = sizeof(rqstp->rq_addr);
X 	msg.msg_iov     = iov;
X 	msg.msg_iovlen  = nr;
-	msg.msg_control = 0;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
X 
X #if LINUX_VERSION_CODE >= 0x020100
X 	msg.msg_flags	= MSG_DONTWAIT;
@@ -308,7 +309,8 @@
X 	msg.msg_namelen = sizeof(rqstp->rq_addr);
X 	msg.msg_iov     = iov;
X 	msg.msg_iovlen  = nr;
-	msg.msg_control = 0;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
X 
X #if LINUX_VERSION_CODE >= 0x020100
X 	msg.msg_flags	= MSG_DONTWAIT;
diff -u --recursive --new-file v2.2.7/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.2.7/linux/net/sunrpc/xprt.c	Tue Mar 23 14:35:48 1999
+++ linux/net/sunrpc/xprt.c	Tue May  4 10:29:07 1999
@@ -200,6 +200,7 @@
X 	msg.msg_name	= (struct sockaddr *) &xprt->addr;
X 	msg.msg_namelen = sizeof(xprt->addr);
X 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
X 
X 	/* Dont repeat bytes */
X 	
@@ -256,6 +257,7 @@
X 	msg.msg_name	= &sin;
X 	msg.msg_namelen = sizeof(sin);
X 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
X 
X 	oldfs = get_fs(); set_fs(get_ds());
X 	result = sock_recvmsg(sock, &msg, len, MSG_DONTWAIT);
@@ -268,6 +270,7 @@
X 	msg.msg_name	= &sin;
X 	msg.msg_namelen = sizeof(sin);
X 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
X 
X 	oldfs = get_fs(); set_fs(get_ds());
X 	result = sock->ops->recvmsg(sock, &msg, len, 1, 0, &alen);
diff -u --recursive --new-file v2.2.7/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.2.7/linux/net/unix/af_unix.c	Mon Mar 29 11:09:12 1999
+++ linux/net/unix/af_unix.c	Mon May 10 09:55:25 1999
@@ -8,7 +8,7 @@
X  *		as published by the Free Software Foundation; either version
X  *		2 of the License, or (at your option) any later version.
X  *
- * Version:	$Id: af_unix.c,v 1.75 1999/03/22 05:02:45 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.76 1999/05/08 05:54:55 davem Exp $
X  *
X  * Fixes:
X  *		Linus Torvalds	:	Assorted bug cures.
@@ -322,7 +322,7 @@
X 	{
X 		if (sk->type==SOCK_STREAM && unix_our_peer(sk, skpair))
X 		{
-			skpair->state_change(skpair);
+			skpair->data_ready(skpair,0);
X 			skpair->shutdown=SHUTDOWN_MASK;	/* No more writes*/
X 		}
X 		unix_unlock(skpair); /* It may now die */
@@ -1409,7 +1409,10 @@
X 			if (mode&SEND_SHUTDOWN)
X 				peer_mode |= RCV_SHUTDOWN;
X 			other->shutdown |= peer_mode;
-			other->state_change(other);
+			if (peer_mode&RCV_SHUTDOWN)
+				other->data_ready(other,0);
+			else
+				other->state_change(other);
X 		}
X 	}
X 	return 0;
diff -u --recursive --new-file v2.2.7/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.2.7/linux/scripts/Menuconfig	Tue Feb 23 15:21:36 1999
+++ linux/scripts/Menuconfig	Sun May  2 09:51:16 1999
@@ -193,7 +193,7 @@
X 	else if [ "$3" = "m" ]; then
X 	    mod_bool "$1" "$2"
X 	else 
-	    define_bool "$2" "$n"
+	    define_bool "$2" n
X 	fi; fi
X }
X 
diff -u --recursive --new-file v2.2.7/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.2.7/linux/scripts/tkgen.c	Tue Feb 23 15:21:36 1999
+++ linux/scripts/tkgen.c	Sun May  2 09:51:16 1999
@@ -930,8 +930,11 @@
X 
X 	case token_hex:
X 	case token_int:
+	    printf( "set %s %s\n", cfg->optionname, cfg->value ? cfg->value : "0");
+	    break;
+
X 	case token_string:
-	    printf( "set %s %s\n", cfg->optionname, cfg->value );
+	    printf( "set %s \"%s\"\n", cfg->optionname, cfg->value ? cfg->value : "");
X 	    break;
X 	}
X     }
diff -u --recursive --new-file v2.2.7/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v2.2.7/linux/scripts/tkparse.c	Tue Feb 23 15:21:36 1999
+++ linux/scripts/tkparse.c	Sun May  2 09:51:16 1999
@@ -496,10 +496,15 @@
X 
X     case token_hex:
X     case token_int:
-    case token_string:
X 	pnt = get_qstring ( pnt, &cfg->label      );
X 	pnt = get_string  ( pnt, &cfg->optionname );
X 	pnt = get_string  ( pnt, &cfg->value      );
+	break;
+
+    case token_string:
+	pnt = get_qstring ( pnt, &cfg->label      );
+	pnt = get_string  ( pnt, &cfg->optionname );
+	pnt = get_qstring  ( pnt, &cfg->value      );
X 	break;
X 
X     case token_if:
SHAR_EOF
true || echo 'restore of patch-2.2.8 failed'
echo 'File patch-2.2.8 is complete' &&
chmod 644 patch-2.2.8 ||
echo 'restore of patch-2.2.8 failed'
Cksum="`cksum < 'patch-2.2.8'`"
if ! test "1861375263 1865967" = "$Cksum"
then
	echo 'patch-2.2.8: original Checksum 1861375263 1865967, current one' "$Cksum" 
	rm -f _shar_wnt_.tmp
	rm -f _shar_seq_.tmp
	exit 1
fi
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo 'You have unpacked the last part.'