diff -u --recursive --new-file v2.3.44/linux/CREDITS linux/CREDITS
--- v2.3.44/linux/CREDITS	Thu Feb 10 17:11:01 2000
+++ linux/CREDITS	Sun Feb 13 18:21:45 2000
@@ -637,13 +637,6 @@
 S: S-114 53 Stockholm
 S: Sweden
 
-N: Stephane Eranian
-E: eranian@hpl.hp.com
-D: Linux/ia64
-S: 1501 Page Mill Rd, MS 1U17
-S: Palo Alto, CA 94304
-S: USA
-
 N: Paal-Kristian Engstad
 E: engstad@intermetrics.com
 D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
@@ -651,6 +644,13 @@
 S: Huntington Beach, California 92649
 S: USA
 
+N: Stephane Eranian
+E: eranian@hpl.hp.com
+D: Linux/ia64
+S: 1501 Page Mill Rd, MS 1U17
+S: Palo Alto, CA 94304
+S: USA
+
 N: Johannes Erdfelt
 E: jerdfelt@valinux.com
 D: Linux/IA-64 bootloader and kernel goop, USB
@@ -1832,17 +1832,17 @@
 S: 13349 Berlin
 S: Germany
 
-N: Nicolas Pitre
-E: nico@cam.org
-D: StrongARM SA1100 support integrator & hacker
-S: Montreal, Quebec, Canada
-
 N: Emanuel Pirker
 E: epirker@edu.uni-klu.ac.at
 D: AIC5800 IEEE 1394, RAW I/O on 1394
 D: Starter of Linux1394 effort
 S: ask per mail for current address
 
+N: Nicolas Pitre
+E: nico@cam.org
+D: StrongARM SA1100 support integrator & hacker
+S: Montreal, Quebec, Canada
+
 N: Ken Pizzini
 E: ken@halcyon.com
 D: CDROM driver "sonycd535" (Sony CDU-535/531)
@@ -2613,13 +2613,6 @@
 S: 3078 Sulphur Spring Court
 S: San Jose, California 95148
 S: USA
-
-N: Alessandro Zummo
-E: azummo@ita.flashnet.it
-W: http://freepage.logicom.it/azummo/
-D: CMI8330 support is sb_card.c
-D: ISAPnP fixes in sb_card.c
-S: Italy
 
 N: Alessandro Zummo
 E: azummo@ita.flashnet.it
diff -u --recursive --new-file v2.3.44/linux/Makefile linux/Makefile
--- v2.3.44/linux/Makefile	Sat Feb 12 11:22:10 2000
+++ linux/Makefile	Sat Feb 12 11:22:20 2000
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 44
+SUBLEVEL = 45
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.44/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c
--- v2.3.44/linux/arch/alpha/kernel/pci_iommu.c	Thu Feb 10 17:11:02 2000
+++ linux/arch/alpha/kernel/pci_iommu.c	Sun Feb 13 10:15:21 2000
@@ -16,7 +16,6 @@
 
 
 #define DEBUG_ALLOC 0
-
 #if DEBUG_ALLOC > 0
 # define DBGA(args...)		printk(KERN_DEBUG ##args)
 #else
@@ -40,6 +39,20 @@
 {
 	return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
 }
+
+static inline long
+calc_order(long size)
+{
+	int order;
+
+	size = (size-1) >> (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
 
 struct pci_iommu_arena *
 iommu_arena_new(dma_addr_t base, unsigned long window_size,
@@ -173,10 +186,6 @@
 	ret = arena->dma_base + dma_ofs * PAGE_SIZE;
 	ret += (unsigned long)cpu_addr & ~PAGE_MASK;
 
-	/* ??? This shouldn't have been needed, since the entries
-	   we've just modified were not in the iommu tlb.  */
-	alpha_mv.mv_pci_tbi(hose, ret, ret + size - 1);
-
 	DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n",
 	     cpu_addr, size, npages, ret, __builtin_return_address(0));
 
@@ -239,11 +248,12 @@
 pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
 {
 	void *cpu_addr;
+	long order = calc_order(size);
 
-	cpu_addr = kmalloc(size, GFP_ATOMIC);
+	cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order);
 	if (! cpu_addr) {
-		printk(KERN_INFO "dma_alloc_consistent: "
-		       "kmalloc failed from %p\n",
+		printk(KERN_INFO "pci_alloc_consistent: "
+		       "get_free_pages failed from %p\n",
 			__builtin_return_address(0));
 		/* ??? Really atomic allocation?  Otherwise we could play
 		   with vmalloc and sg if we can't find contiguous memory.  */
@@ -253,11 +263,11 @@
 
 	*dma_addrp = pci_map_single(pdev, cpu_addr, size);
 	if (*dma_addrp == 0) {
-		kfree_s(cpu_addr, size);
+		free_pages((unsigned long)cpu_addr, order);
 		return NULL;
 	}
 		
-	DBGA2("dma_alloc_consistent: %lx -> [%p,%x] from %p\n",
+	DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n",
 	      size, cpu_addr, *dma_addrp, __builtin_return_address(0));
 
 	return cpu_addr;
@@ -275,32 +285,33 @@
 		    dma_addr_t dma_addr)
 {
 	pci_unmap_single(pdev, dma_addr, size);
-	kfree_s(cpu_addr, size);
+	free_pages((unsigned long)cpu_addr, calc_order(size));
 
-	DBGA2("dma_free_consistent: [%x,%lx] from %p\n",
+	DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
 	      dma_addr, size, __builtin_return_address(0));
 }
 
 
 /* Classify the elements of the scatterlist.  Write dma_address
    of each element with:
-	0   : Not mergable.
-	1   : Followers all physically adjacent.
-	[23]: Followers all virtually adjacent.
-	-1  : Not leader.
+	0   : Followers all physically adjacent.
+	1   : Followers all virtually adjacent.
+	-1  : Not leader, physically adjacent to previous.
+	-2  : Not leader, virtually adjacent to previous.
    Write dma_length of each leader with the combined lengths of
    the mergable followers.  */
 
 static inline void
-sg_classify(struct scatterlist *sg, struct scatterlist *end)
+sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
 {
 	unsigned long next_vaddr;
 	struct scatterlist *leader;
+	long leader_flag, leader_length;
 
 	leader = sg;
-	leader->dma_address = 0;
-	leader->dma_length = leader->length;
-	next_vaddr = (unsigned long)leader->address + leader->length;
+	leader_flag = 0;
+	leader_length = leader->length;
+	next_vaddr = (unsigned long)leader->address + leader_length;
 
 	for (++sg; sg < end; ++sg) {
 		unsigned long addr, len;
@@ -309,20 +320,24 @@
 
 		if (next_vaddr == addr) {
 			sg->dma_address = -1;
-			leader->dma_address |= 1;
-			leader->dma_length += len;
-		} else if (((next_vaddr | addr) & ~PAGE_MASK) == 0) {
-			sg->dma_address = -1;
-			leader->dma_address |= 2;
-			leader->dma_length += len;
+			leader_length += len;
+		} else if (((next_vaddr | addr) & ~PAGE_MASK) == 0 && virt_ok) {
+			sg->dma_address = -2;
+			leader_flag = 1;
+			leader_length += len;
 		} else {
+			leader->dma_address = leader_flag;
+			leader->dma_length = leader_length;
 			leader = sg;
-			leader->dma_address = 0;
-			leader->dma_length = len;
+			leader_flag = 0;
+			leader_length = len;
 		}
 
 		next_vaddr = addr + len;
 	}
+
+	leader->dma_address = leader_flag;
+	leader->dma_length = leader_length;
 }
 
 /* Given a scatterlist leader, choose an allocation method and fill
@@ -334,21 +349,21 @@
 	dma_addr_t max_dma)
 {
 	unsigned long paddr = virt_to_phys(leader->address);
-	unsigned long size = leader->dma_length;
+	long size = leader->dma_length;
 	struct scatterlist *sg;
 	unsigned long *ptes;
 	long npages, dma_ofs, i;
 
 	/* If everything is physically contiguous, and the addresses
 	   fall into the direct-map window, use it.  */
-	if (leader->dma_address < 2
+	if (leader->dma_address == 0
 	    && paddr + size + __direct_map_base - 1 <= max_dma
 	    && paddr + size <= __direct_map_size) {
 		out->dma_address = paddr + __direct_map_base;
 		out->dma_length = size;
 
-		DBGA2("sg_fill: [%p,%lx] -> direct %x\n",
-		      leader->address, size, out->dma_address);
+		DBGA("    sg_fill: [%p,%lx] -> direct %x\n",
+		     leader->address, size, out->dma_address);
 
 		return 0;
 	}
@@ -365,48 +380,70 @@
 	out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
 	out->dma_length = size;
 
-	DBGA("sg_fill: [%p,%lx] -> sg %x\n",
-	     leader->address, size, out->dma_address);
+	DBGA("    sg_fill: [%p,%lx] -> sg %x np %ld\n",
+	     leader->address, size, out->dma_address, npages);
 
 	ptes = &arena->ptes[dma_ofs];
 	sg = leader;
-	do {
-		paddr = virt_to_phys(sg->address);
-		npages = calc_npages((paddr & ~PAGE_MASK) + sg->length);
-
-		DBGA("        (%ld) [%p,%x]\n",
-		      sg - leader, sg->address, sg->length);
+	if (0 && leader->dma_address == 0) {
+		/* All physically contiguous.  We already have the
+		   length, all we need is to fill in the ptes.  */
 
-		paddr &= PAGE_MASK;
+		paddr = virt_to_phys(sg->address) & PAGE_MASK;
 		for (i = 0; i < npages; ++i, paddr += PAGE_SIZE)
 			*ptes++ = mk_iommu_pte(paddr);
 
-		++sg;
-	} while (sg < end && sg->dma_address == -1);
+#if DEBUG_ALLOC > 0
+		DBGA("    (0) [%p,%x] np %ld\n",
+		     sg->address, sg->length, npages);
+		for (++sg; sg < end && (int) sg->dma_address < 0; ++sg)
+			DBGA("        (%ld) [%p,%x] cont\n",
+			     sg - leader, sg->address, sg->length);
+#endif
+	} else {
+		/* All virtually contiguous.  We need to find the
+		   length of each physically contiguous subsegment
+		   to fill in the ptes.  */
+		do {
+			struct scatterlist *last_sg = sg;
+
+			size = sg->length;
+			paddr = virt_to_phys(sg->address);
+
+			while (sg+1 < end && (int) sg[1].dma_address == -1) {
+				size += sg[1].length;
+				sg++;
+			}
+
+			npages = calc_npages((paddr & ~PAGE_MASK) + size);
+
+			paddr &= PAGE_MASK;
+			for (i = 0; i < npages; ++i, paddr += PAGE_SIZE)
+				*ptes++ = mk_iommu_pte(paddr);
+
+#if DEBUG_ALLOC > 0
+			DBGA("    (%ld) [%p,%x] np %ld\n",
+			     last_sg - leader, last_sg->address,
+			     last_sg->length, npages);
+			while (++last_sg <= sg) {
+				DBGA("        (%ld) [%p,%x] cont\n",
+				     last_sg - leader, last_sg->address,
+				     last_sg->length);
+			}
+#endif
+		} while (++sg < end && (int) sg->dma_address < 0);
+	}
 
 	return 1;
 }
 
-/* TODO: Only use the iommu when it helps.  Non-mergable scatterlist
-   entries might as well use direct mappings.  */
-
 int
 pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents)
 {
 	struct scatterlist *start, *end, *out;
 	struct pci_controler *hose;
 	struct pci_iommu_arena *arena;
-	dma_addr_t max_dma, fstart, fend;
-
-	/* If pci_tbi is not available, we must not be able to control
-	   an iommu.  Direct map everything, no merging.  */
-	if (! alpha_mv.mv_pci_tbi) {
-		for (end = sg + nents; sg < end; ++sg) {
-			sg->dma_address = virt_to_bus(sg->address);
-			sg->dma_length = sg->length;
-		}
-		return nents;
-	}
+	dma_addr_t max_dma;
 
 	/* Fast path single entry scatterlists.  */
 	if (nents == 1) {
@@ -416,50 +453,42 @@
 		return sg->dma_address != 0;
 	}
 
-	hose = pdev ? pdev->sysdata : pci_isa_hose;
-	max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
-	arena = hose->sg_pci;
-	if (!arena || arena->dma_base + arena->size > max_dma)
-		arena = hose->sg_isa;
 	start = sg;
 	end = sg + nents;
-	fstart = -1;
-	fend = 0;
-	
+
 	/* First, prepare information about the entries.  */
-	sg_classify(sg, end);
+	sg_classify(sg, end, alpha_mv.mv_pci_tbi != 0);
 
-	/* Second, iterate over the scatterlist leaders and allocate
+	/* Second, figure out where we're going to map things.  */
+	if (alpha_mv.mv_pci_tbi) {
+		hose = pdev ? pdev->sysdata : pci_isa_hose;
+		max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
+		arena = hose->sg_pci;
+		if (!arena || arena->dma_base + arena->size > max_dma)
+			arena = hose->sg_isa;
+	} else {
+		max_dma = -1;
+		arena = NULL;
+		hose = NULL;
+	}
+
+	/* Third, iterate over the scatterlist leaders and allocate
 	   dma space as needed.  */
 	for (out = sg; sg < end; ++sg) {
 		int ret;
 
-		if (sg->dma_address == -1)
+		if ((int) sg->dma_address < 0)
 			continue;
 
 		ret = sg_fill(sg, end, out, arena, max_dma);
 		if (ret < 0)
 			goto error;
-		else if (ret > 0) {
-			dma_addr_t ts, te;
-
-			ts = out->dma_address;
-			te = ts + out->dma_length - 1;
-			if (fstart > ts)
-				fstart = ts;
-			if (fend < te)
-				fend = te;
-		}
 		out++;
 	}
 
-	/* ??? This shouldn't have been needed, since the entries
-	   we've just modified were not in the iommu tlb.  */
-	if (fend)
-		alpha_mv.mv_pci_tbi(hose, fstart, fend);
-
 	if (out - start == 0)
 		printk(KERN_INFO "pci_map_sg failed: no entries?\n");
+	DBGA("pci_map_sg: %ld entries\n", out - start);
 
 	return out - start;
 
@@ -496,9 +525,11 @@
 	arena = hose->sg_pci;
 	if (!arena || arena->dma_base + arena->size > max_dma)
 		arena = hose->sg_isa;
+
+	DBGA("pci_unmap_sg: %d entries\n", nents);
+
 	fstart = -1;
 	fend = 0;
-
 	for (end = sg + nents; sg < end; ++sg) {
 		unsigned long addr, size;
 
@@ -508,7 +539,8 @@
 		if (addr >= __direct_map_base
 		    && addr < __direct_map_base + __direct_map_size) {
 			/* Nothing to do.  */
-			DBGA2("pci_unmap_sg: direct [%lx,%lx]\n", addr, size);
+			DBGA("    (%ld) direct [%lx,%lx]\n",
+			      sg - end + nents, addr, size);
 		} else {
 			long npages, ofs;
 			dma_addr_t tend;
@@ -523,7 +555,8 @@
 			if (fend < tend)
 				fend = tend;
 
-			DBGA2("pci_unmap_sg: sg [%lx,%lx]\n", addr, size);
+			DBGA("    (%ld) sg [%lx,%lx]\n",
+			      sg - end + nents, addr, size);
 		}
 	}
 	if (fend)
diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.3.44/linux/arch/arm/kernel/armksyms.c	Fri Jan 21 18:19:15 2000
+++ linux/arch/arm/kernel/armksyms.c	Sun Feb 13 10:47:01 2000
@@ -188,6 +188,10 @@
 EXPORT_SYMBOL(uaccess_user);
 #endif
 
+EXPORT_SYMBOL(consistent_alloc);
+EXPORT_SYMBOL(consistent_free);
+EXPORT_SYMBOL(consistent_sync);
+
 	/* gcc lib functions */
 EXPORT_SYMBOL_NOVERS(__gcc_bcmp);
 EXPORT_SYMBOL_NOVERS(__ashldi3);
@@ -234,5 +238,8 @@
 EXPORT_SYMBOL_NOVERS(__down_interruptible_failed);
 EXPORT_SYMBOL_NOVERS(__down_trylock_failed);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 
 EXPORT_SYMBOL(get_wchan);
diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.3.44/linux/arch/arm/kernel/entry-common.S	Fri Jan 21 18:19:15 2000
+++ linux/arch/arm/kernel/entry-common.S	Sun Feb 13 10:47:01 2000
@@ -15,26 +15,28 @@
 #define HARVARD_CACHE
 #endif
 
+		.macro	get_softirq, rd
+#ifdef __SMP__
+#error SMP not supported
+#else
+		ldr	\rd, __softirq_state
+#endif
+		.endm
+
 		.globl	ret_from_sys_call
 
 		.align	5
 fast_syscall_return:
-		str	r0, [sp, #S_R0 + S_OFF]		@ returned r0
+		str	r0, [sp, #S_R0 + S_OFF]	@ returned r0
 slow_syscall_return:
 		add	sp, sp, #S_OFF
-ret_from_sys_call:
-#ifdef HARVARD_CACHE
-		ldr	r0, bh_data
-		ldr	r4, bh_data+4
-#else
-		adr	r0, bh_data
-		ldmia	r0, {r0, r4}
-#endif
-		ldr	r0, [r0]
-		ldr	r1, [r4]
+ret_from_sys_call:				@ external entry
+		get_softirq r0
+		ldmia	r0, {r0, r1}
+		mov	r4, #1			@ flag this as being syscall return
 		tst	r0, r1
-		blne	SYMBOL_NAME(do_bottom_half)
-ret_with_reschedule:
+		blne	SYMBOL_NAME(do_softirq)
+ret_with_reschedule:				@ external entry (__irq_usr)
 		get_current_task r5
 		ldr	r0, [r5, #TSK_NEED_RESCHED]
 		ldr	r1, [r5, #TSK_SIGPENDING]
@@ -43,30 +45,23 @@
 		teq	r1, #0			@ check for signals
 		bne	ret_signal
 
-ret_from_all:	restore_user_regs
+ret_from_all:	restore_user_regs		@ internal
 
-ret_signal:	mov	r1, sp
+ret_signal:	mov	r1, sp			@ internal
 		adrsvc	al, lr, ret_from_all
 		mov	r2, r4
 		b	SYMBOL_NAME(do_signal)
 
-ret_reschedule:	adrsvc	al, lr, ret_with_reschedule
+ret_reschedule:	adrsvc	al, lr, ret_with_reschedule	@ internal
 		b	SYMBOL_NAME(schedule)
 
 		.globl	ret_from_exception
-ret_from_exception:
-#ifdef HARVARD_CACHE
-		ldr	r0, bh_data
-		ldr	r1, bh_data + 4
-#else
-		adr	r0, bh_data
+ret_from_exception:				@ external entry
+		get_softirq r0
 		ldmia	r0, {r0, r1}
-#endif
-		ldr	r0, [r0]
-		ldr	r1, [r1]
 		mov	r4, #0
 		tst	r0, r1
-		blne	SYMBOL_NAME(do_bottom_half)
+		blne	SYMBOL_NAME(do_softirq)
 		ldr	r0, [sp, #S_PSR]
 		tst	r0, #3			@ returning to user mode?
 		beq	ret_with_reschedule
@@ -147,8 +142,8 @@
 
 		.align	5
 
-bh_data:	.word	SYMBOL_NAME(bh_mask)
-		.word	SYMBOL_NAME(bh_active)
+__softirq_state:
+		.word	SYMBOL_NAME(softirq_state)
 
 ENTRY(sys_call_table)
 #include "calls.S"
diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.3.44/linux/arch/arm/kernel/irq.c	Fri Oct 22 13:21:44 1999
+++ linux/arch/arm/kernel/irq.c	Sun Feb 13 10:47:01 2000
@@ -237,16 +237,8 @@
 
 	irq_exit(cpu, irq);
 
-	/*
-	 * This should be conditional: we should really get
-	 * a return code from the irq handler to tell us
-	 * whether the handler wants us to do software bottom
-	 * half handling or not..
-	 */
-	if (1) {
-		if (bh_active & bh_mask)
-			do_bottom_half();
-	}
+	if (softirq_state[cpu].active & softirq_state[cpu].mask)
+		do_softirq();
 }
 
 #if defined(CONFIG_ARCH_ACORN)
diff -u --recursive --new-file v2.3.44/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c
--- v2.3.44/linux/arch/arm/kernel/semaphore.c	Fri Oct 22 13:21:44 1999
+++ linux/arch/arm/kernel/semaphore.c	Sun Feb 13 10:47:01 2000
@@ -164,6 +164,126 @@
 	return 1;
 }
 
+struct rw_semaphore *down_read_failed_biased(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	add_wait_queue(&sem->wait, &wait);	/* put ourselves at the head of the list */
+
+	for (;;) {
+		if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
+			break;
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+		if (!sem->read_bias_granted)
+			schedule();
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
+{
+        struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
+
+	for (;;) {
+		if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
+			break;
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+		if (!sem->write_bias_granted)
+			schedule();
+	}
+
+	remove_wait_queue(&sem->write_bias_wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	/* if the lock is currently unbiased, awaken the sleepers
+	 * FIXME: this wakes up the readers early in a bit of a
+	 * stampede -> bad!
+	 */
+	if (atomic_read(&sem->count) >= 0)
+		wake_up(&sem->wait);
+
+	return sem;
+}
+
+/* Wait for the lock to become unbiased.  Readers
+ * are non-exclusive. =)
+ */
+struct rw_semaphore *down_read_failed(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	/* this takes care of granting the lock */
+	__up_op_read(sem, __rwsem_wake);
+
+	add_wait_queue(&sem->wait, &wait);
+
+	while (atomic_read(&sem->count) < 0) {
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+		if (atomic_read(&sem->count) >= 0)
+			break;
+		schedule();
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+/* Wait for the lock to become unbiased. Since we're
+ * a writer, we'll make ourselves exclusive.
+ */
+struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	/* this takes care of granting the lock */
+	__up_op_write(sem, __rwsem_wake);
+
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	while (atomic_read(&sem->count) < 0) {
+		set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+		if (atomic_read(&sem->count) >= 0)
+			break;	/* we must attempt to aquire or bias the lock */		schedule();
+	}
+
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+
+	return sem;
+}
+
+/* Called when someone has done an up that transitioned from
+ * negative to non-negative, meaning that the lock has been
+ * granted to whomever owned the bias.
+ */
+struct rw_semaphore *rwsem_wake_readers(struct rw_semaphore *sem)
+{
+	if (xchg(&sem->read_bias_granted, 1))
+		BUG();
+	wake_up(&sem->wait);
+	return sem;
+}
+
+struct rw_semaphore *rwsem_wake_writer(struct rw_semaphore *sem)
+{
+	if (xchg(&sem->write_bias_granted, 1))
+		BUG();
+	wake_up(&sem->write_bias_wait);
+	return sem;
+}
+
 /*
  * The semaphore operations have a special calling sequence that
  * allow us to do a simpler in-line version of them. These routines
@@ -174,30 +294,65 @@
  * registers (r0 to r3, ip and lr) except r0 in the cases where it
  * is used as a return value..
  */
-asm(".align	5
+asm("	.section	.text.lock, \"ax\"
+	.align	5
 	.globl	__down_failed
 __down_failed:
 	stmfd	sp!, {r0 - r3, ip, lr}
 	bl	__down
-	ldmfd	sp!, {r0 - r3, ip, pc}");
+	ldmfd	sp!, {r0 - r3, ip, pc}
 
-asm(".align	5
+	.align	5
 	.globl	__down_interruptible_failed
 __down_interruptible_failed:
 	stmfd	sp!, {r1 - r3, ip, lr}
 	bl	__down_interruptible
-	ldmfd	sp!, {r1 - r3, ip, pc}");
+	ldmfd	sp!, {r1 - r3, ip, pc}
 
-asm(".align	5
+	.align	5
 	.globl	__down_trylock_failed
 __down_trylock_failed:
 	stmfd	sp!, {r1 - r3, ip, lr}
 	bl	__down_trylock
-	ldmfd	sp!, {r1 - r3, ip, pc}");
+	ldmfd	sp!, {r1 - r3, ip, pc}
 
-asm(".align	5
+	.align	5
 	.globl	__up_wakeup
 __up_wakeup:
 	stmfd	sp!, {r0 - r3, ip, lr}
 	bl	__up
-	ldmfd	sp!, {r0 - r3, ip, pc}");
+	ldmfd	sp!, {r0 - r3, ip, pc}
+
+	.align	5
+	.globl	__down_read_failed
+__down_read_failed:
+	stmfd	sp!, {r0 - r3, ip, lr}
+	bcc	1f
+	bl	down_read_failed_biased
+	ldmfd	sp!, {r0 - r3, ip, pc}
+1:	bl	down_read_failed
+	/***/
+
+	.align	5
+	.globl	__down_write_failed
+__down_write_failed:
+	stmfd	sp!, {r0 - r3, ip, lr}
+	bcc	1f
+	bl	down_write_failed_biased
+	ldmfd	sp!, {r0 - r3, ip, pc}
+1:	bl	down_write_failed
+	/***/
+
+	.align	5
+	.globl	__rwsem_wake
+__rwsem_wake:
+	stmfd	sp!, {r0 - r3, ip, lr}
+	beq	1f
+	bl	rwsem_wake_readers
+	ldmfd	sp!, {r0 - r3, ip, pc}
+1:	bl	rwsem_wake_writer
+	ldmfd	sp!, {r0 - r3, ip, pc}
+
+	.previous
+	");
+
diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile
--- v2.3.44/linux/arch/arm/mm/Makefile	Fri Oct 22 13:21:44 1999
+++ linux/arch/arm/mm/Makefile	Sun Feb 13 10:47:01 2000
@@ -8,8 +8,8 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET	:= mm.o
-O_OBJS		:= init.o extable.o fault-$(PROCESSOR).o mm-$(PROCESSOR).o \
-		   small_page.o
+O_OBJS		:= consistent.o extable.o fault-$(PROCESSOR).o init.o \
+		   mm-$(PROCESSOR).o small_page.o
 
 ifeq ($(CONFIG_CPU_26),y)
   O_OBJS	+= proc-arm2,3.o
diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c
--- v2.3.44/linux/arch/arm/mm/consistent.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/consistent.c	Sun Feb 13 10:47:01 2000
@@ -0,0 +1,102 @@
+/*
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+/* Pure 2^n version of get_order */
+extern __inline__ int __get_order(unsigned long size)
+{
+	int order;
+
+	size = (size-1) >> (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
+}
+
+/*
+ * This allocates one page of cache-coherent memory space and returns
+ * both the virtual and a "dma" address to that space.  It is not clear
+ * whether this could be called from an interrupt context or not.  For
+ * now, we expressly forbid it, especially as some of the stuff we do
+ * here is not interrupt context safe.
+ */
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
+{
+	int order;
+	unsigned long page;
+	struct vm_struct *area;
+	void *ret;
+
+	if (in_interrupt())
+		BUG();
+
+	order = __get_order(size);
+
+	page = __get_free_pages(gfp, order);
+	if (!page)
+		goto no_page;
+
+	memset((void *)page, 0, PAGE_SIZE << order);
+	clean_cache_area(page, PAGE_SIZE << order);
+
+	*dma_handle = virt_to_bus((void *)page);
+
+	area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */
+	if (!area)
+		goto no_area;
+
+	ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0);
+	if (ret)
+		return ret;
+
+no_area:
+	free_pages(page, order);
+no_page:
+	BUG();
+	return NULL;
+}
+
+/*
+ * free a page as defined by the above mapping.  We expressly forbid
+ * calling this from interrupt context.
+ */
+void consistent_free(void *vaddr)
+{
+	if (in_interrupt())
+		BUG();
+
+	__iounmap(vaddr);
+}
+
+/*
+ * make an area consistent.
+ */
+void consistent_sync(void *vaddr, size_t size, int rw)
+{
+	switch (rw) {
+	case 0:
+		BUG();
+	case 1:	/* invalidate only */
+		dma_cache_inv(vaddr, size);
+		break;
+	case 2:	/* writeback only */
+		dma_cache_wback(vaddr, size);
+		break;
+	case 3:	/* writeback and invalidate */
+		dma_cache_wback_inv(vaddr, size);
+		break;
+	}
+}
diff -u --recursive --new-file v2.3.44/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.3.44/linux/arch/arm/mm/proc-arm6,7.S	Fri Jan 21 18:19:16 2000
+++ linux/arch/arm/mm/proc-arm6,7.S	Sun Feb 13 10:47:01 2000
@@ -103,9 +103,9 @@
 		.align
 
 ENTRY(cpu_arm6_data_abort)
-Ldata_simple:
 		ldr	r4, [r0]			@ read instruction causing problem
 		mov	r2, r4, lsr #19			@ r2 b1 = L
+Ldata_simple:
 		and	r2, r2, #2			@ check read/write bit
 		mrc	p15, 0, r0, c6, c0, 0		@ get FAR
 		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
diff -u --recursive --new-file v2.3.44/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c
--- v2.3.44/linux/arch/arm/nwfpe/fpmodule.c	Fri Oct 22 13:21:44 1999
+++ linux/arch/arm/nwfpe/fpmodule.c	Sun Feb 13 10:47:01 2000
@@ -128,23 +128,41 @@
 
 void float_raise(signed char flags)
 {
+  register unsigned int fpsr, cumulativeTraps;
+  
 #ifdef CONFIG_DEBUG_USER
   printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n",
 	 current->comm, current->pid, flags,
 	 __builtin_return_address(0), userRegisters[15]);
 #endif
 
+  /* Keep SoftFloat exception flags up to date.  */
   float_exception_flags |= flags;
-  if (readFPSR() & (flags << 16))
-  {
-    /* raise exception */
+
+  /* Read fpsr and initialize the cumulativeTraps.  */
+  fpsr = readFPSR();
+  cumulativeTraps = 0;
+  
+  /* For each type of exception, the cumulative trap exception bit is only
+     set if the corresponding trap enable bit is not set.  */
+  if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
+     cumulativeTraps |= BIT_IXC;  
+  if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
+     cumulativeTraps |= BIT_UFC;  
+  if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
+     cumulativeTraps |= BIT_OFC;  
+  if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
+     cumulativeTraps |= BIT_DZC;  
+  if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
+     cumulativeTraps |= BIT_IOC;  
+
+  /* Set the cumulative exceptions flags.  */
+  if (cumulativeTraps)
+    writeFPSR(fpsr | cumulativeTraps);
+
+  /* Raise an exception if necessary.  */
+  if (fpsr & (flags << 16))
     fp_send_sig(SIGFPE, current, 1);
-  }
-  else
-  {
-    /* set the cumulative exceptions flags */
-    writeFPSR(flags);
-  }
 }
 
 module_init(fpe_init);
diff -u --recursive --new-file v2.3.44/linux/arch/arm/nwfpe/fpsr.h linux/arch/arm/nwfpe/fpsr.h
--- v2.3.44/linux/arch/arm/nwfpe/fpsr.h	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpsr.h	Sun Feb 13 10:47:01 2000
@@ -63,12 +63,12 @@
 #define MASK_SYSTEM_CONTROL	0x0000ff00
 #define MASK_TRAP_STRICT	0x00001f00
 
-#define BIT_AC	0x00100000	/* use alternative C-flag definition
+#define BIT_AC	0x00001000	/* use alternative C-flag definition
 				   for compares */
-#define BIT_EP	0x00080000	/* use expanded packed decimal format */
-#define BIT_SO	0x00040000	/* select synchronous operation of FPA */
-#define BIT_NE	0x00020000	/* NaN exception bit */
-#define BIT_ND	0x00010000	/* no denormalized numbers bit */
+#define BIT_EP	0x00000800	/* use expanded packed decimal format */
+#define BIT_SO	0x00000400	/* select synchronous operation of FPA */
+#define BIT_NE	0x00000200	/* NaN exception bit */
+#define BIT_ND	0x00000100	/* no denormalized numbers bit */
 
 /* CUMULATIVE EXCEPTION FLAGS BYTE
 ---------------------------------- */
diff -u --recursive --new-file v2.3.44/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S
--- v2.3.44/linux/arch/i386/boot/bootsect.S	Tue Nov 23 22:42:20 1999
+++ linux/arch/i386/boot/bootsect.S	Sun Feb 13 10:16:36 2000
@@ -106,9 +106,8 @@
 	pushw	%ds
 	ldsw	%fs:(%bx), %si		# ds:si is source
 	movb	$6, %cl			# copy 12 bytes
-	cld
 	pushw	%di			# di = 0x4000-12.
-	rep
+	rep				# don't need cld -> done on line 66
 	movsw
 	popw	%di
 	popw	%ds
@@ -140,20 +139,7 @@
 	jmp	load_setup
 
 ok_load_setup:
-# Get disk drive parameters, specifically nr of sectors/track.
-
-#if 0
-
-# bde - the Phoenix BIOS manual says function 0x08 only works for fixed
-# disks.  It doesn't work for one of my BIOS's (1987 Award).  It was
-# fatal not to check the error code.
-
-	xorb	%dl, %dl
-	movb	$0x08, %ah		# AH=8 is get drive parameters
-	int	$0x13
-	xorb	%ch, %ch
-
-#else
+# Get disk drive parameters, specifically number of sectors/track.
 
 # It seems that there is no BIOS call to get the number of sectors.
 # Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
@@ -176,7 +162,6 @@
 	movw	$0x0201, %ax		# service 2, 1 sector
 	int	$0x13
 	jc	probe_loop		# try next value
-#endif
 
 got_sectors:
 	movw	$INITSEG, %ax
@@ -200,11 +185,11 @@
 # Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
 # depending on the number of sectors we pretend to know we have.
 
-	movw	%cs:root_dev, %ax
+	movw	root_dev, %ax
 	orw	%ax, %ax
 	jne	root_defined
 	
-	movw	%cs:sectors, %bx
+	movw	sectors, %bx
 	movw	$0x0208, %ax		# /dev/ps0 - 1.2Mb
 	cmpw	$15, %bx
 	je	root_defined
@@ -219,7 +204,7 @@
 	
 	movb	$0, %al			# /dev/fd0 - autodetect
 root_defined:
-	movw	%ax, %cs:root_dev
+	movw	%ax, root_dev
 
 # After that (everything loaded), we jump to the setup-routine
 # loaded directly after the bootblock:
diff -u --recursive --new-file v2.3.44/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.44/linux/arch/i386/defconfig	Thu Feb 10 17:11:03 2000
+++ linux/arch/i386/defconfig	Sun Feb 13 18:48:07 2000
@@ -270,15 +270,15 @@
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_TULIP is not set
 # CONFIG_DGRS is not set
 CONFIG_EEXPRESS_PRO100=y
 # CONFIG_NE2K_PCI is not set
+# CONFIG_8139TOO is not set
 # CONFIG_SIS900 is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
@@ -453,7 +453,6 @@
 # CONFIG_SYSV_FS is not set
 # CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
 
diff -u --recursive --new-file v2.3.44/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.3.44/linux/arch/i386/kernel/pci-pc.c	Sat Feb 12 11:22:10 2000
+++ linux/arch/i386/kernel/pci-pc.c	Sun Feb 13 10:37:41 2000
@@ -1057,8 +1057,8 @@
 static unsigned int pcibios_irq_mask = 0xfff8;
 
 static unsigned pcibios_irq_penalty[16] = {
-	1000, 1000, 1000, 10, 10, 0, 0, 10,
-	0, 0, 0, 0, 10, 100, 100, 100
+	10000, 10000, 10000, 100, 100, 0, 0, 100,
+	0, 0, 0, 0, 100, 1000, 1000, 1000
 };
 
 static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *rt, int pin, int assign)
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.3.44/linux/arch/ia64/config.in	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/config.in	Sun Feb 13 10:30:38 2000
@@ -3,6 +3,8 @@
 mainmenu_option next_comment
 comment 'General setup'
 
+define_bool CONFIG_IA64 y
+
 choice 'IA-64 system type'					\
 	"Generic		CONFIG_IA64_GENERIC		\
 	 HP-simulator		CONFIG_IA64_HP_SIM		\
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S
--- v2.3.44/linux/arch/ia64/ia32/ia32_entry.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/ia32/ia32_entry.S	Sun Feb 13 10:30:38 2000
@@ -144,7 +144,7 @@
 	data8 sys32_settimeofday
 	data8 sys_getgroups	  /* 80 */
 	data8 sys_setgroups
-	data8 sys_ni_syscall
+	data8 old_select
 	data8 sys_symlink
 	data8 sys_ni_syscall
 	data8 sys_readlink	  /* 85 */
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c
--- v2.3.44/linux/arch/ia64/ia32/ia32_signal.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/ia32/ia32_signal.c	Sun Feb 13 10:30:38 2000
@@ -342,7 +342,16 @@
 }
 
 asmlinkage int
-sys32_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack)
+sys32_sigreturn(
+int arg0,
+int arg1,
+int arg2,
+int arg3,
+int arg4,
+int arg5,
+int arg6,
+int arg7,
+unsigned long stack)
 {
        struct pt_regs *regs = (struct pt_regs *) &stack;
        struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8);
@@ -375,7 +384,16 @@
 }      
 
 asmlinkage int
-sys32_rt_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack)
+sys32_rt_sigreturn(
+int arg0,
+int arg1,
+int arg2,
+int arg3,
+int arg4,
+int arg5,
+int arg6,
+int arg7,
+unsigned long stack)
 {
        struct pt_regs *regs = (struct pt_regs *) &stack;
        struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4);
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- v2.3.44/linux/arch/ia64/ia32/sys_ia32.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/ia32/sys_ia32.c	Sun Feb 13 10:30:38 2000
@@ -240,18 +240,29 @@
 		return -EINVAL;
 	if (prot & PROT_WRITE)
 		prot |= PROT_EXEC;
+#ifdef	DDD
+#else	// DDD
+	prot |= PROT_WRITE;
+#endif	// DDD
 	front = NULL;
 	back = NULL;
 	if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) {
 		front = kmalloc(addr - baddr, GFP_KERNEL);
 		memcpy(front, (void *)baddr, addr - baddr);
 	}
-	if ((addr + len) & ~PAGE_MASK && get_user(c, (char *)(addr + len)) == 0) {
+#ifndef	DDD
+	if (addr)
+#endif
+	if (((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) {
 		back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL);
 		memcpy(back, addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));
 	}
 	if ((r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0)) < 0)
 		return(r);
+#ifndef	DDD
+	if (addr == 0)
+		addr = r;
+#endif	// DDD
 	if (back) {
 		memcpy(addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));
 		kfree(back);
@@ -315,7 +326,11 @@
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
+#ifdef	DDD
 	if ((a.flags & MAP_FIXED) && ((a.addr & ~PAGE_MASK) || (a.offset & ~PAGE_MASK))) {
+#else	// DDD
+	if (1) {
+#endif	// DDD
 		unlock_kernel();
 		up(&current->mm->mmap_sem);
 		error = do_mmap_fake(file, a.addr, a.len, a.prot, a.flags, a.offset);
@@ -665,7 +680,7 @@
 };
 
 static void
-xlate_dirent(void *dirent, long n)
+xlate_dirent(void *dirent64, void *dirent32, long n)
 {
 	long off;
 	struct dirent *dirp;
@@ -673,9 +688,9 @@
 
 	off = 0;
 	while (off < n) {
-		dirp = (struct dirent *)(dirent + off);
+		dirp = (struct dirent *)(dirent64 + off);
+		dirp32 = (struct dirent32 *)(dirent32 + off);
 		off += dirp->d_reclen;
-		dirp32 = (struct dirent32 *)dirp;
 		dirp32->d_ino = dirp->d_ino;
 		dirp32->d_off = (unsigned int)dirp->d_off;
 		dirp32->d_reclen = dirp->d_reclen;
@@ -685,26 +700,27 @@
 }
 
 asmlinkage long
-sys32_getdents(unsigned int fd, void * dirent, unsigned int count)
+sys32_getdents(unsigned int fd, void * dirent32, unsigned int count)
 {
 	long n;
+	void *dirent64;
 
-	if ((n = sys_getdents(fd, dirent, count)) < 0)
+	dirent64 = (unsigned long)(dirent32 + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+	if ((n = sys_getdents(fd, dirent64, count - (dirent64 - dirent32))) < 0)
 		return(n);
-	xlate_dirent(dirent, n);
+	xlate_dirent(dirent64, dirent32, n);
 	return(n);
 }
 
 asmlinkage int
-sys32_readdir(unsigned int fd, void * dirent, unsigned int count)
+sys32_readdir(unsigned int fd, void * dirent32, unsigned int count)
 {
 	int n;
-	struct dirent *dirp;
+	struct dirent dirent64;
 
-	if ((n = old_readdir(fd, dirent, count)) < 0)
+	if ((n = old_readdir(fd, &dirent64, count)) < 0)
 		return(n);
-	dirp = (struct dirent *)dirent;
-	xlate_dirent(dirent, dirp->d_reclen);
+	xlate_dirent(&dirent64, dirent32, dirent64.d_reclen);
 	return(n);
 }
 
@@ -807,6 +823,23 @@
 	kfree(bits);
 out_nofds:
 	return ret;
+}
+
+struct sel_arg_struct {
+	unsigned int n;
+	unsigned int inp;
+	unsigned int outp;
+	unsigned int exp;
+	unsigned int tvp;
+};
+
+asmlinkage int old_select(struct sel_arg_struct *arg)
+{
+	struct sel_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+	return sys32_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 }
 
 struct rusage32 {
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c
--- v2.3.44/linux/arch/ia64/kernel/efi.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/efi.c	Sun Feb 13 10:30:38 2000
@@ -15,7 +15,6 @@
  *
  * Implemented EFI runtime services and virtual mode calls.  --davidm
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -166,14 +165,12 @@
 		      case EFI_BOOT_SERVICES_CODE:
 		      case EFI_BOOT_SERVICES_DATA:
 		      case EFI_CONVENTIONAL_MEMORY:
-#ifndef CONFIG_IA64_VIRTUAL_MEM_MAP
 			if (md->phys_addr > 1024*1024*1024UL) {
 				printk("Warning: ignoring %luMB of memory above 1GB!\n",
 				       md->num_pages >> 8);
 				md->type = EFI_UNUSABLE_MEMORY;
 				continue;
 			}
-#endif
 
 			curr.start = PAGE_OFFSET + md->phys_addr;
 			curr.end   = curr.start + (md->num_pages << 12);
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S
--- v2.3.44/linux/arch/ia64/kernel/entry.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/entry.S	Sun Feb 13 10:30:38 2000
@@ -496,18 +496,27 @@
 (p7)	br.cond.spnt.few handle_syscall_error	// handle potential syscall failure
 
 ia64_leave_kernel:
-	// check & deliver software interrupts (bottom half handlers):
+	// check & deliver software interrupts:
 
-	movl r2=bh_active		// sheesh, why aren't these two in
-	movl r3=bh_mask			// a struct??
+#ifdef CONFIG_SMP
+	adds	r2=IA64_TASK_PROCESSOR_OFFSET,r13
+	movl	r3=softirq_state
 	;;
-	ld8 r2=[r2]
-	ld8 r3=[r3]
+	ld4	r2=[r2]
+	;;
+	shladd	r3=r2,3,r3
+#else
+	movl r3=softirq_state
+#endif
+	;;
+	ld8 r2=[r3]		// r3 is guaranteed to be 8-byte aligned!
+	;;
+	shr r3=r2,32
 	;;
 	and r2=r2,r3
 	;;
-	cmp.ne p6,p7=r2,r0		// any soft interrupts ready for delivery?
-(p6)	br.call.dpnt.few rp=invoke_do_bottom_half
+	cmp4.ne p6,p7=r2,r0
+(p6)	br.call.spnt.many rp=invoke_do_softirq
 1:
 (pKern)	br.cond.dpnt.many restore_all	// yup -> skip check for rescheduling & signal delivery
 
@@ -751,20 +760,20 @@
 #endif /* CONFIG_SMP */
 
 	/*
-	 * Invoke do_bottom_half() while preserving in0-in7, which may be needed
+	 * Invoke do_softirq() while preserving in0-in7, which may be needed
 	 * in case a system call gets restarted.
 	 */
-	.proc invoke_do_bottom_half
-invoke_do_bottom_half:
+	.proc invoke_do_softirq
+invoke_do_softirq:
 	alloc loc0=ar.pfs,8,2,0,0
 	mov loc1=rp
 	;;
-	br.call.sptk.few rp=do_bottom_half
+	br.call.sptk.few rp=do_softirq
 .ret9:
 	mov ar.pfs=loc0
 	mov rp=loc1
 	br.ret.sptk.many rp
-	.endp invoke_do_bottom_half
+	.endp invoke_do_softirq
 
 	/*
 	 * Invoke schedule() while preserving in0-in7, which may be needed
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S
--- v2.3.44/linux/arch/ia64/kernel/gate.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/gate.S	Sun Feb 13 10:30:38 2000
@@ -132,6 +132,7 @@
 	ld8 r8=[base0]				// restore (perhaps modified) CFM0, EC0, and CPL0
 	cmp.ne p8,p0=r14,r15			// do we need to restore the rbs?
 (p8)	br.cond.spnt.few restore_rbs		// yup -> (clobbers r14 and r16)
+	;;
 back_from_restore_rbs:
 	{
 	  and r9=0x7f,r8			// r9  <- CFM0.sof
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S
--- v2.3.44/linux/arch/ia64/kernel/head.S	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/head.S	Sun Feb 13 10:30:38 2000
@@ -133,6 +133,7 @@
 #endif /* CONFIG_IA64_EARLY_PRINTK */
 
 	alloc r2=ar.pfs,8,0,2,0
+	;;
 #ifdef CONFIG_SMP
 (isAP)	br.call.sptk.few rp=smp_callin
 .ret1:
@@ -174,7 +175,7 @@
 	st8.nta [in0]=r16,8
 	st8.nta [r19]=r17,8
 	br.cloop.sptk.few 1b
-
+	;;
 	mov ar.lc=r20			// restore ar.lc
 	br.ret.sptk.few b0
 	.endp ia64_save_debug_regs
@@ -197,7 +198,7 @@
 	mov dbr[r18]=r16
 	mov ibr[r18]=r17
 	br.cloop.sptk.few 1b
-
+	;;
 	mov ar.lc=r20			// restore ar.lc
 	br.ret.sptk.few b0
 	.endp ia64_load_debug_regs
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c
--- v2.3.44/linux/arch/ia64/kernel/irq.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/irq.c	Sun Feb 13 10:30:38 2000
@@ -128,6 +128,18 @@
 	return p - buf;
 }
 
+int usbfix;
+
+static int __init
+usbfix_option (char *str)
+{
+	printk("irq: enabling USB workaround\n");
+	usbfix = 1;
+	return 1;
+}
+
+__setup("usbfix", usbfix_option);
+
 /*
  * That's where the IVT branches when we get an external
  * interrupt. This branches to the correct hardware IRQ handler via
@@ -146,7 +158,8 @@
 	unsigned long eoi_ptr;
  
 # ifdef CONFIG_USB
-	disable_usb();
+	if (usbfix)
+		disable_usb();
 # endif
 	/*
 	 * Stop IPIs by getting the ivr_read_lock
@@ -170,7 +183,8 @@
 	spin_unlock(&ivr_read_lock);
 
 # ifdef CONFIG_USB
-	reenable_usb();
+	if (usbfix)
+		reenable_usb();
 # endif
 
 # ifndef CONFIG_SMP
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/irq_lock.c linux/arch/ia64/kernel/irq_lock.c
--- v2.3.44/linux/arch/ia64/kernel/irq_lock.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/irq_lock.c	Sun Feb 13 10:30:38 2000
@@ -26,7 +26,7 @@
 spinlock_t global_irq_lock;
 atomic_t global_irq_count;
 atomic_t global_bh_count;
-atomic_t global_bh_lock;
+spinlock_t global_bh_lock;
 
 #define INIT_STUCK (1<<26)
 
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/pci-dma.c linux/arch/ia64/kernel/pci-dma.c
--- v2.3.44/linux/arch/ia64/kernel/pci-dma.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/pci-dma.c	Sun Feb 13 10:30:38 2000
@@ -21,7 +21,7 @@
 extern __inline__ unsigned long
 get_order (unsigned long size)
 {
-	unsigned long order = ia64_fls(size);
+	unsigned long order = ia64_fls(size - 1) + 1;
 
 	printk ("get_order: size=%lu, order=%lu\n", size, order);
 
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c
--- v2.3.44/linux/arch/ia64/kernel/pci.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/pci.c	Sun Feb 13 10:30:38 2000
@@ -226,14 +226,3 @@
 pcibios_align_resource (void *data, struct resource *res, unsigned long size)
 {
 }
-
-#if 0 /*def CONFIG_PROC_FS*/
-/*
- * This is an ugly hack to get a (weak) unresolved reference to something that is
- * in drivers/pci/proc.c.  Without this, the file does not get linked in at all
- * (I suspect the reason this isn't needed on Linux/x86 is that most people compile
- * with module support, in which case the EXPORT_SYMBOL() stuff will ensure the
- * code gets linked in.  Sigh...  --davidm 99/12/20.
- */
-asm ("data8 proc_bus_pci_add");
-#endif
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c
--- v2.3.44/linux/arch/ia64/kernel/smp.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/smp.c	Sun Feb 13 10:30:38 2000
@@ -57,7 +57,7 @@
 unsigned long cpu_online_map = 1;
 #endif
 
-volatile int cpu_number_map[NR_CPUS] = { -1, };      /* SAPIC ID -> Logical ID */
+volatile int __cpu_number_map[NR_CPUS] = { -1, };    /* SAPIC ID -> Logical ID */
 volatile int __cpu_logical_map[NR_CPUS] = { -1, };   /* logical ID -> SAPIC ID */
 int smp_num_cpus = 1;		
 int bootstrap_processor = -1;                        /* SAPIC ID of BSP */
@@ -586,7 +586,7 @@
 
 alive:
 	/* Remember the AP data */
-	cpu_number_map[cpuid] = cpunum;
+	__cpu_number_map[cpuid] = cpunum;
 #ifdef CONFIG_KDB
         cpu_online_map |= (1<<cpunum);
         printk ("DEBUGGER: cpu_online_map = 0x%08x\n", cpu_online_map);
@@ -612,12 +612,12 @@
 	extern int acpi_apic_map[32];
 
 	/* Take care of some initial bookkeeping.  */
-	memset(&cpu_number_map, -1, sizeof(cpu_number_map));
+	memset(&__cpu_number_map, -1, sizeof(__cpu_number_map));
 	memset(&__cpu_logical_map, -1, sizeof(__cpu_logical_map));
 	memset(&ipi_op, 0, sizeof(ipi_op));
 
 	/* Setup BSP mappings */
-	cpu_number_map[bootstrap_processor] = 0;
+	__cpu_number_map[bootstrap_processor] = 0;
 	__cpu_logical_map[0] = bootstrap_processor;
 	current->processor = bootstrap_processor;
 
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c
--- v2.3.44/linux/arch/ia64/kernel/sys_ia64.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/kernel/sys_ia64.c	Sun Feb 13 10:30:38 2000
@@ -2,8 +2,8 @@
  * This file contains various system calls that have different calling
  * conventions on different platforms.
  *
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile
--- v2.3.44/linux/arch/ia64/lib/Makefile	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/lib/Makefile	Sun Feb 13 10:30:38 2000
@@ -3,7 +3,7 @@
 #
 
 .S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@
 
 OBJS  = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o		\
 	__moddi3.o __modsi3.o __umoddi3.o __umodsi3.o		\
diff -u --recursive --new-file v2.3.44/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c
--- v2.3.44/linux/arch/ia64/tools/print_offsets.c	Thu Feb 10 17:11:03 2000
+++ linux/arch/ia64/tools/print_offsets.c	Sun Feb 13 10:30:38 2000
@@ -47,6 +47,7 @@
     { "IA64_TASK_FLAGS_OFFSET",		offsetof (struct task_struct, flags) },
     { "IA64_TASK_SIGPENDING_OFFSET",	offsetof (struct task_struct, sigpending) },
     { "IA64_TASK_NEED_RESCHED_OFFSET",	offsetof (struct task_struct, need_resched) },
+    { "IA64_TASK_PROCESSOR_OFFSET",	offsetof (struct task_struct, processor) },
     { "IA64_TASK_THREAD_OFFSET",	offsetof (struct task_struct, thread) },
     { "IA64_TASK_THREAD_KSP_OFFSET",	offsetof (struct task_struct, thread.ksp) },
     { "IA64_TASK_PID_OFFSET",		offsetof (struct task_struct, pid) },
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.3.44/linux/arch/m68k/config.in	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/config.in	Sun Feb 13 11:21:42 2000
@@ -161,10 +161,17 @@
    comment 'SCSI support type (disk, tape, CD-ROM)'
 
    dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+   if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
+      int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
+   fi
    dep_tristate '  SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+   if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then
+      int  'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2
+   fi
    dep_tristate '  SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
    if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
       bool '    Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+      int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
    fi
    dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
 
@@ -273,9 +280,13 @@
 	 tristate '  Apollo 3c505 support' CONFIG_APOLLO_ELPLUS
       fi
       if [ "$CONFIG_MAC" = "y" ]; then
-	 bool '  Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
-#	 bool '  Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
-	 bool '  Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
+	 bool '  Macintosh NS 8390 based ethernet cards' CONFIG_MAC8390
+	 tristate '  Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)' CONFIG_MACSONIC
+	 tristate '  Macintosh SMC 9194 based ethernet cards' CONFIG_SMC9194
+	 tristate '  Macintosh CS89x0 based ethernet cards' CONFIG_MAC89x0
+	 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+		bool '  Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)' CONFIG_MACMACE
+	 fi
       fi
       if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
 	 tristate '  MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
@@ -352,12 +363,6 @@
       define_bool CONFIG_BUSMOUSE y
    fi
 fi
-if [ "$CONFIG_MAC" = "y" ]; then
-   bool 'Mac ADB mouse support' CONFIG_ADBMOUSE
-   if [ "$CONFIG_ADBMOUSE" != "n" ]; then
-      define_bool CONFIG_BUSMOUSE y
-   fi
-fi
 if [ "$CONFIG_ATARI" = "y" ]; then
    tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
    tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
@@ -384,7 +389,20 @@
    fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
-   bool 'Mac SCC serial support' CONFIG_MAC_SCC
+   tristate 'Macintosh serial support' CONFIG_MAC_SCC
+   bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB
+   if [ "$CONFIG_ADB" = "y" ]; then
+      bool '   Support for ADB keyboard' CONFIG_ADB_KEYBOARD 
+      bool '   Support for ADB mouse' CONFIG_ADBMOUSE
+      bool '   Include Mac II ADB driver' CONFIG_ADB_MACII
+      bool '   Include Mac IIsi ADB driver' CONFIG_ADB_MACIISI
+      bool '   Include CUDA ADB driver' CONFIG_ADB_CUDA
+      bool '   Include IOP (IIfx/Quadra 9x0) ADB driver' CONFIG_ADB_IOP
+      bool '   Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU68K
+   fi
+   if [ "$CONFIG_ADBMOUSE" = "y" ]; then
+      define_bool CONFIG_BUSMOUSE y
+   fi
 fi
 if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
    tristate 'HP DCA serial support' CONFIG_HPDCA
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- v2.3.44/linux/arch/m68k/kernel/Makefile	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/kernel/Makefile	Sun Feb 13 11:21:42 2000
@@ -27,6 +27,8 @@
 
 head.o: head.S m68k_defs.h
 
+entry.o: entry.S m68k_defs.h
+
 sun3-head.o: sun3-head.S m68k_defs.h
 
 m68k_defs.h: m68k_defs.c m68k_defs.head
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.3.44/linux/arch/m68k/kernel/entry.S	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/kernel/entry.S	Sun Feb 13 11:21:42 2000
@@ -236,12 +236,12 @@
 #endif
 	/* check if we need to do software interrupts */
 
-	movel	SYMBOL_NAME(bh_active),%d0
-	andl	SYMBOL_NAME(bh_mask),%d0
+	movel	SYMBOL_NAME(softirq_state),%d0
+	andl	SYMBOL_NAME(softirq_state)+4,%d0
 	jeq	SYMBOL_NAME(ret_from_exception)
 
 	pea	SYMBOL_NAME(ret_from_exception)
-	jra	SYMBOL_NAME(do_bottom_half)
+	jra	SYMBOL_NAME(do_softirq)
 
 
 /* Handler for uninitialized and spurious interrupts */
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.3.44/linux/arch/m68k/kernel/m68k_ksyms.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Sun Feb 13 11:21:42 2000
@@ -18,7 +18,6 @@
 #include <asm/checksum.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
-#include <asm/m68kserial.h>
 
 asmlinkage long long __ashrdi3 (long long, int);
 asmlinkage long long __lshrdi3 (long long, int);
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile
--- v2.3.44/linux/arch/m68k/mac/Makefile	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/Makefile	Sun Feb 13 11:21:42 2000
@@ -10,6 +10,6 @@
 O_TARGET := mac.o
 OX_OBJS  := mac_ksyms.o
 O_OBJS	 := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
-		macboing.o debug.o misc.o
+		baboon.o macboing.o debug.o misc.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c
--- v2.3.44/linux/arch/m68k/mac/adb-bus.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/m68k/mac/adb-bus.c	Wed Dec 31 16:00:00 1969
@@ -1,2699 +0,0 @@
-/*
- *	MACII	ADB keyboard handler.
- *		Copyright (c) 1997 Alan Cox
- *
- *	Derived from code 
- *		Copyright (C) 1996 Paul Mackerras.
- *
- *	MSch (9/97) Partial rewrite of interrupt handler to MacII style
- *		ADB handshake, based on:
- *			- Guide to Mac Hardware
- *			- Guido Koerber's session with a logic analyzer
- *
- *	MSch (1/98) Integrated start of IIsi driver by Robert Thompson
- */
- 
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include "via6522.h"
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/adb.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/setup.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-
-
-#define MACII		/* For now - will be a switch */
-
-/* Bits in B data register: all active low */
-#define TREQ		0x08		/* Transfer request (input) */
-#define TACK		0x10		/* Transfer acknowledge (output) */
-#define TIP		0x20		/* Transfer in progress (output) */
-
-/* Bits in B data register: ADB transaction states MacII */
-#define ST_MASK		0x30		/* mask for selecting ADB state bits */
-/* ADB transaction states according to GMHW */
-#define ST_CMD		0x00		/* ADB state: command byte */
-#define ST_EVEN		0x10		/* ADB state: even data byte */
-#define ST_ODD		0x20		/* ADB state: odd data byte */
-#define ST_IDLE		0x30		/* ADB state: idle, nothing to send */
-
-/* Bits in ACR */
-#define SR_CTRL		0x1c		/* Shift register control bits */
-#ifdef USE_ORIG
-#define SR_EXT		0x1c		/* Shift on external clock */
-#else
-#define SR_EXT		0x0c		/* Shift on external clock */
-#endif
-#define SR_OUT		0x10		/* Shift out if 1 */
-
-/* Bits in IFR and IER */
-#define IER_SET		0x80		/* set bits in IER */
-#define IER_CLR		0		/* clear bits in IER */
-#define SR_INT		0x04		/* Shift register full/empty */
-#define SR_DATA		0x08		/* Shift register data */
-#define SR_CLOCK	0x10		/* Shift register clock */
-
-/* JRT */
-#define ADB_DELAY 150
-
-static struct adb_handler {
-    void (*handler)(unsigned char *, int, struct pt_regs *);
-} adb_handler[16];
-
-static enum adb_state {
-    idle,
-    sent_first_byte,
-    sending,
-    reading,
-    read_done,
-    awaiting_reply
-} adb_state;
-
-static struct adb_request *current_req;
-static struct adb_request *last_req;
-static unsigned char cuda_rbuf[16];
-static unsigned char *reply_ptr;
-static int reply_len;
-static int reading_reply;
-static int data_index;
-static int first_byte;
-static int prefix_len;
-
-static int status = ST_IDLE|TREQ;
-static int last_status;
-
-static int driver_running = 0;
-
-/*static int adb_delay;*/
-int in_keybinit = 1;
-
-static void adb_start(void);
-extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs);
-extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
-extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs);
-extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs);
-static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs);
-
-static void adb_hw_setup_IIsi(void);
-static void adb_hw_setup_cuda(void);
-
-/*
- * debug level 10 required for ADB logging (should be && debug_adb, ideally)
- */
-
-extern int console_loglevel;
-
-/*
- * Misc. defines for testing - should go to header :-(
- */
-
-#define ADBDEBUG_STATUS		(1)
-#define ADBDEBUG_STATE		(2)
-#define ADBDEBUG_READ		(4)
-#define ADBDEBUG_WRITE		(8)
-#define ADBDEBUG_START		(16)
-#define ADBDEBUG_RETRY		(32)
-#define ADBDEBUG_POLL		(64)
-#define ADBDEBUG_INT		(128)
-#define ADBDEBUG_PROT		(256)
-#define ADBDEBUG_SRQ		(512)
-#define ADBDEBUG_REQUEST	(1024)
-#define ADBDEBUG_INPUT		(2048)
-#define ADBDEBUG_DEVICE		(4096)
-
-#define ADBDEBUG_IISI		(8192)
-
-
-/*#define DEBUG_ADB*/
-
-#ifdef DEBUG_ADB
-#define ADBDEBUG	(ADBDEBUG_INPUT | ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST)
-#else
-#define ADBDEBUG	(0)
-#endif
-
-#define TRY_CUDA
-
-void adb_bus_init(void)
-{
-	unsigned long flags;
-	unsigned char c, i;
-	
-	save_flags(flags);
-	cli();
-	
-	/*
-	 *	Setup ADB
-	 */
-	 
-	switch(macintosh_config->adb_type)
-	{
-	
-		case MAC_ADB_II:
-			printk("adb: MacII style keyboard/mouse driver.\n");
-			/* Set the lines up. We want TREQ as input TACK|TIP as output */
-		 	via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
-			/*
-			 * Docs suggest TREQ should be output - that seems nuts
-			 * BSD agrees here :-)
-			 * Setup vPCR ??
-			 */
-
-#ifdef USE_ORIG
-		 	/* Lower the bus signals (MacII is active low it seems ???) */
-		 	via_write(via1, vBufB, via_read(via1, vBufB)&~TACK);
-#else
-			/* Corresponding state: idle (clear state bits) */
-		 	via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
-			last_status = (via_read(via1, vBufB)&~ST_MASK);
-#endif
-		 	/* Shift register on input */
-		 	c=via_read(via1, vACR);
-		 	c&=~SR_CTRL;		/* Clear shift register bits */
-		 	c|=SR_EXT;		/* Shift on external clock; out or in? */
-		 	via_write(via1, vACR, c);
-		 	/* Wipe any pending data and int */
-		 	via_read(via1, vSR);
-
-		 	/* This is interrupts on enable SR for keyboard */
-		 	via_write(via1, vIER, IER_SET|SR_INT); 
-		 	/* This clears the interrupt bit */
-		 	via_write(via1, vIFR, SR_INT);
-
-		 	/*
-		 	 *	Ok we probably ;) have a ready to use adb bus. Its also
-		 	 *	hopefully idle (Im assuming the mac didnt leave a half
-		 	 *	complete transaction on booting us).
- 			 */
- 
-			request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, 
-				    "adb interrupt", adb_interrupt);
-			adb_state = idle;
-			break;
-			/*
-			 *	Unsupported; but later code doesn't notice !!
-			 */
-		case MAC_ADB_CUDA:
-			printk("adb: CUDA interface.\n");
-#if 0
-			/* don't know what to set up here ... */
-			adb_state = idle;
-			/* Set the lines up. We want TREQ as input TACK|TIP as output */
-		 	via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
-#endif
-			adb_hw_setup_cuda();
-			adb_state = idle;
-			request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, 
-				    "adb CUDA interrupt", adb_cuda_interrupt);
-			break;
-		case MAC_ADB_IISI:
-			printk("adb: Using IIsi hardware.\n");
-			printk("\tDEBUG_JRT\n");
-			/* Set the lines up. We want TREQ as input TACK|TIP as output */
-		 	via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
-
-			/*
-			 * MSch: I'm pretty sure the setup is mildly wrong
-			 * for the IIsi. 
-			 */
-			/* Initial state: idle (clear state bits) */
-		 	via_write(via1, vBufB, (via_read(via1, vBufB) & ~(TIP|TACK)) );
-			last_status = (via_read(via1, vBufB)&~ST_MASK);
-		 	/* Shift register on input */
-		 	c=via_read(via1, vACR);
-		 	c&=~SR_CTRL;		/* Clear shift register bits */
-		 	c|=SR_EXT;		/* Shift on external clock; out or in? */
-		 	via_write(via1, vACR, c);
-		 	/* Wipe any pending data and int */
-		 	via_read(via1, vSR);
-
-		 	/* This is interrupts on enable SR for keyboard */
-		 	via_write(via1, vIER, IER_SET|SR_INT); 
-		 	/* This clears the interrupt bit */
-		 	via_write(via1, vIFR, SR_INT);
-
-			/* get those pesky clock ticks we missed while booting */
-			for ( i = 0; i < 60; i++) {
-				udelay(ADB_DELAY);
-				adb_hw_setup_IIsi();
-				udelay(ADB_DELAY);
-				if (via_read(via1, vBufB) & TREQ)
-					break;
-			}
-			if (i == 60)
-				printk("adb_IIsi: maybe bus jammed ??\n");
-
-		 	/*
-		 	 *	Ok we probably ;) have a ready to use adb bus. Its also
- 			 */
-			request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, 
-				    "adb interrupt", adb_cuda_interrupt);
-			adb_state = idle;
- 			break;
-		default:
-			printk("adb: Unknown hardware interface.\n");
-		nosupp:
-			printk("adb: Interface unsupported.\n");
-			restore_flags(flags);	
-			return;
-	}
-
-	/*
-	 * XXX: interrupt only registered if supported HW !!
-	 * -> unsupported HW will just time out on keyb_init!
-	 */
-#if 0
-	request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, 
-		    "adb interrupt", adb_interrupt);
-#endif
-#ifdef DEBUG_ADB_INTS
-	request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, 
-		    "adb clock interrupt", adb_clock_interrupt);
-	request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK, 
-		    "adb data interrupt", adb_data_interrupt);
-#endif
-
-	printk("adb: init done.\n");
-	restore_flags(flags);	
-} 
-	
-void adb_hw_setup_cuda(void)
-{
-	int		x;
-	unsigned long	flags;
-
-	printk("CUDA: HW Setup:");
-
-	save_flags(flags);
-	cli();
-
-	if (console_loglevel == 10) 
-		printk("  1,");
-
-	/* Set the direction of the cuda signals, TIP+TACK are output TREQ is an input */
-	via_write( via1, vDirB, via_read( via1, vDirB ) | TIP | TACK );
-	via_write( via1, vDirB, via_read( via1, vDirB ) & ~TREQ );
-
-	if (console_loglevel == 10) 
-		printk("2,");
-
-	/* Set the clock control. Set to shift data in by external clock CB1 */
-	via_write( via1, vACR, ( via_read(via1, vACR ) | SR_EXT ) & ~SR_OUT );
-
-	if (console_loglevel == 10) 
-		printk("3,");
-
-	/* Clear any possible Cuda interrupt */
-	x = via_read( via1, vSR );
-
-	if (console_loglevel == 10) 
-		printk("4,");
-
-	/* Terminate transaction and set idle state */
-	via_write( via1, vBufB, via_read( via1, vBufB ) | TIP | TACK );
-
-	if (console_loglevel == 10) 
-		printk("5,");
-
-	/* Delay 4 mS for ADB reset to complete */
-	udelay(4000);
-
-	if (console_loglevel == 10) 
-		printk("6,");
-
-	/* Clear pending interrupts... */
-	x = via_read( via1, vSR );
-
-	if (console_loglevel == 10) 
-		printk("7,");
-	/* Issue a sync transaction, TACK asserted while TIP negated */
-	via_write( via1, vBufB, via_read( via1, vBufB ) & ~TACK );
-
-	if (console_loglevel == 10) 
-		printk("8,");
-
-	/* Wait for the sync acknowledgement, Cuda to assert TREQ */
-	while( ( via_read( via1, vBufB ) & TREQ ) != 0 )
-		barrier();
-
-	if (console_loglevel == 10) 
-		printk("9,");
-
-	/* Wait for the sync acknowledment interrupt */
-	while( ( via_read( via1, vIFR ) & SR_INT ) == 0 )
-		barrier();
-
-	if (console_loglevel == 10) 
-		printk("10,");
-
-	/* Clear pending interrupts... */
-	x = via_read( via1, vSR );
-
-	if (console_loglevel == 10) 
-		printk("11,");
-
-	/* Terminate the sync cycle by negating TACK */
-	via_write( via1, vBufB, via_read( via1, vBufB ) | TACK );
-
-	if (console_loglevel == 10) 
-		printk("12,");
-
-	/* Wait for the sync termination acknowledgement, Cuda to negate TREQ */
-	while( ( via_read( via1, vBufB ) & TREQ ) == 0 )
-		barrier();
-
-	if (console_loglevel == 10) 
-		printk("13,");
-
-	/* Wait for the sync termination acknowledment interrupt */
-	while( ( via_read( via1, vIFR ) & SR_INT ) == 0 )
-		barrier();
-
-	if (console_loglevel == 10) 
-		printk("14,");
-
-	/* Terminate transaction and set idle state, TIP+TACK negate */
-	via_write( via1, vBufB, via_read( via1, vBufB ) | TIP );
-
-	if (console_loglevel == 10) 
-		printk("15 !");
-
-	/* Clear pending interrupts... */
-	x = via_read( via1, vSR );
-
-	restore_flags(flags);
-
-	printk("\nCUDA: HW Setup done!\n");
-}
-
-void adb_hw_setup_IIsi(void)
-{
-	int dummy;
-	long poll_timeout;
-
-	printk("adb_IIsi: cleanup!\n");
-
-	/* ??? */
-	udelay(ADB_DELAY);
-
-	/* disable SR int. */
-	via_write(via1, vIER, IER_CLR|SR_INT);
-	/* set SR to shift in */
-	via_write(via1, vACR, via_read(via1, vACR ) & ~SR_OUT);
-
-	/* this is required, especially on faster machines */
-	udelay(ADB_DELAY);
-
-	if (!(via_read(via1, vBufB) & TREQ)) { /* IRQ on */
-		/* start frame */
-		via_write(via1, vBufB,via_read(via1,vBufB) | TIP);
-
-		while (1) {
-			/* poll for ADB interrupt and watch for timeout */
-			/* if time out, keep going in hopes of not hanging the
-			 * ADB chip - I think */
-			poll_timeout = ADB_DELAY * 5;
-			while ( !(via_read(via1, vIFR) & SR_INT) 
-				&& (poll_timeout-- > 0) )
-				dummy = via_read(via1, vBufB);
-
-			dummy = via_read(via1, vSR);	/* reset interrupt flag */
-
-			/* perhaps put in a check here that ignores all data
-			 * after the first ADB_MAX_MSG_LENGTH bytes ??? */
-
-			/* end of frame reached ?? */
-			if (via_read(via1, vBufB) & TREQ)
-				break;
-
-			/* set ACK */
-			via_write(via1,vBufB,via_read(via1, vBufB) | TACK);
-			/* delay */
-			udelay(ADB_DELAY);
-			/* clear ACK */
-			via_write(via1,vBufB,via_read(via1, vBufB) & ~TACK);
-		}
-		/* end frame */
-		via_write(via1, vBufB,via_read(via1,vBufB) & ~TIP);
-		/* probably don't need to delay this long */
-		udelay(ADB_DELAY);
-	}
-	/* re-enable SR int. */
-	via_write(via1, vIER, IER_SET|SR_INT);
-}
-
-#define WAIT_FOR(cond, what)				\
-    do {						\
-	for (x = 1000; !(cond); --x) {			\
-	    if (x == 0) {				\
-		printk("Timeout waiting for " what);	\
-		return 0;				\
-	    }						\
-	    __delay(100*160);					\
-	}						\
-    } while (0)
-
-/* 
- *	Construct and send an adb request 
- *	This function is the main entry point into the ADB driver from 
- *	kernel code; it takes the request data supplied and populates the
- *	adb_request structure.
- *	In order to keep this interface independent from any assumption about
- *	the underlying ADB hardware, we take requests in CUDA format here, 
- *	the ADB packet 'prefixed' with a packet type code.
- *	Non-CUDA hardware is confused by this, so we strip the packet type
- *	here depending on hardware type ...
- */
-int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
-	     int nbytes, ...)
-{
-	va_list list;
-	int i, start;
-
-	va_start(list, nbytes);
-
-	/*
-	 * skip first byte if not CUDA 
-	 */
-	if (macintosh_config->adb_type == MAC_ADB_II) {
-		start =  va_arg(list, int);
-		nbytes--;
-	}
-	req->nbytes = nbytes;
-	req->done = done;
-#if (ADBDEBUG & ADBDEBUG_REQUEST)
-	if (console_loglevel == 10)
-		printk("adb_request, data bytes: ");
-#endif
-	for (i = 0; i < nbytes; ++i) {
-		req->data[i] = va_arg(list, int);
-#if (ADBDEBUG & ADBDEBUG_REQUEST)
-		if (console_loglevel == 10)
-			printk("%x ", req->data[i]);
-#endif
-	}
-#if (ADBDEBUG & ADBDEBUG_REQUEST)
-	if (console_loglevel == 10)
-		printk(" !\n");
-#endif
-	va_end(list);
-	/* 
-	 * XXX: This might be fatal if no reply is generated (i.e. Listen) ! 
-	 * Currently, the interrupt handler 'fakes' a reply on non-TALK 
-	 * commands for this reason.
-	 * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA 
-	 * Macs, and some mechanism to remember the last issued TALK
-	 * request for resending it repeatedly on timeout!
-	 */
-	req->reply_expected = 1;
-	return adb_send_request(req);
-}
-
-/* 
- *	Construct an adb request for later sending
- *	This function only populates the adb_request structure, without 
- *	actually queueing it.
- *	Reason: Poll requests and Talk requests need to be handled in a way
- *	different from 'user' requests; no reply_expected is set and 
- *	Poll requests need to be placed at the head of the request queue.
- *	Using adb_request results in implicit queueing at the tail of the 
- *	request queue (duplicating the Poll) with reply_expected set.
- *	No adjustment of packet data is necessary, as this mechanisnm is not
- *	used by CUDA hardware (Autopoll used instead).
- */
-int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *),
-	     int nbytes, ...)
-{
-	va_list list;
-	int i;
-
-	req->nbytes = nbytes;
-	req->done = done;
-	va_start(list, nbytes);
-#if (ADBDEBUG & ADBDEBUG_REQUEST)
-	if (console_loglevel == 10)
-		printk("adb__build_request, data bytes: ");
-#endif
-	/*
-	 * skip first byte if not CUDA ?
-	 */
-	for (i = 0; i < nbytes; ++i) {
-		req->data[i] = va_arg(list, int);
-#if (ADBDEBUG & ADBDEBUG_REQUEST)
-		if (console_loglevel == 10)
-			printk("%x ", req->data[i]);
-#endif
-	}
-#if (ADBDEBUG & ADBDEBUG_REQUEST)
-	if (console_loglevel == 10)
-		printk(" !\n");
-#endif
-	va_end(list);
-
-	req->reply_expected = 0;
-	return 0;
-}
-
-/*
- *	Send an ADB poll (Talk, tagged on the front of the request queue)
- */
-void adb_queue_poll(void)
-{
-	static int pod=0;
-	static int in_poll=0;
-	static struct adb_request r;
-	unsigned long flags;
-
-	if(in_poll)
-		printk("Double poll!\n");
-
-	in_poll++;
-	pod++;
-	if(pod>7) /* 15 */
-		pod=0;
-
-#if (ADBDEBUG & ADBDEBUG_POLL)
-	if (console_loglevel == 10)
-		printk("adb: Polling %d\n",pod);
-#endif
-
-	if (macintosh_config->adb_type == MAC_ADB_II)
-		/* XXX: that's a TALK, register 0, MacII version */
-		adb_build_request(&r,NULL, 1, (pod<<4|0xC));
-	else
-		/* CUDA etc. version */
-		adb_build_request(&r,NULL, 2, 0, (pod<<4|0xC));
-
-	r.reply_expected=0;
-	r.done=NULL;
-	r.sent=0;
-	r.got_reply=0;
-	r.reply_len=0;
-	save_flags(flags);
-	cli();
-	/* Poll inserted at head of queue ... */
-	r.next=current_req;
-	current_req=&r;
-	restore_flags(flags);
-	adb_start();
-	in_poll--;
-}
-
-/*
- *	Send an ADB retransmit (Talk, appended to the request queue)
- */
-void adb_retransmit(int device)
-{
-	static int in_retransmit=0;
-	static struct adb_request rt;
-	unsigned long flags;
-
-	if(in_retransmit)
-		printk("Double retransmit!\n");
-
-	in_retransmit++;
-
-#if (ADBDEBUG & ADBDEBUG_POLL)
-	if (console_loglevel == 10)
-		printk("adb: Sending retransmit: %d\n", device);
-#endif
-
-	/* MacII version */
-	adb_build_request(&rt,NULL, 1, (device<<4|0xC));
-
-	rt.reply_expected = 0;
-	rt.done           = NULL;
-	rt.sent           = 0;
-	rt.got_reply      = 0;
-	rt.reply_len      = 0;
-	rt.next           = NULL;
-
-	save_flags(flags);
-	cli();
-
-	/* Retransmit inserted at tail of queue ... */
-
-	if (current_req != NULL) 
-	{
-		last_req->next = &rt;
-		last_req = &rt;
-	}
-	else
-	{
-		current_req = &rt;
-		last_req = &rt;
-	}
-
-	/* always restart driver (send_retransmit used in place of adb_start!)*/
-
-	if (adb_state == idle)
-		adb_start();
-
-	restore_flags(flags);
-	in_retransmit--;
-}
-
-/*
- * Queue an ADB request; start ADB transfer if necessary
- */
-int adb_send_request(struct adb_request *req)
-{
-	unsigned long flags;
-
-	req->next = 0;
-	req->sent = 0;
-	req->got_reply = 0;
-	req->reply_len = 0;
-	save_flags(flags); 
-	cli();
-
-	if (current_req != NULL) 
-	{
-		last_req->next = req;
-		last_req = req;
-	}
-	else
-	{
-		current_req = req;
-		last_req = req;
-		if (adb_state == idle)
-			adb_start();
-	}
-
-	restore_flags(flags);
-	return 0;
-}
-
-static int nclock, ndata;
-
-static int need_poll    = 0;
-static int command_byte = 0;
-static int last_reply   = 0;
-static int last_active  = 0;
-
-static struct adb_request *retry_req;
-
-/*
- * Start sending ADB packet 
- */
-static void adb_start(void)
-{
-	unsigned long flags;
-	struct adb_request *req;
-
-	/*
-	 * We get here on three 'sane' conditions:
-	 * 1) called from send_adb_request, if adb_state == idle
-	 * 2) called from within adb_interrupt, if adb_state == idle 
-	 *    (after receiving, or after sending a LISTEN) 
-	 * 3) called from within adb_interrupt, if adb_state == sending 
-	 *    and no reply is expected (immediate next command).
-	 * Maybe we get here on SRQ as well ??
-	 */
-
-	/* get the packet to send */
-	req = current_req;
-	/* assert adb_state == idle */
-	if (adb_state != idle) {
-		printk("ADB: adb_start called while driver busy (%p %x %x)!\n",
-			req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
-		return;
-	}
-	if (req == 0)
-		return;
-	save_flags(flags); 
-	cli();
-	
-#if (ADBDEBUG & ADBDEBUG_START)
-	if (console_loglevel == 10)
-		printk("adb_start: request %p ", req);
-#endif
-
-	nclock = 0;
-	ndata  = 0;
-
-	/* 
-	 * IRQ signaled ?? (means ADB controller wants to send, or might 
-	 * be end of packet if we were reading)
-	 */
-	if ((via_read(via1, vBufB) & TREQ) == 0) 
-	{
-		switch(macintosh_config->adb_type)
-		{
-			/*
-			 *	FIXME - we need to restart this on a timer
-			 *	or a collision at boot hangs us.
-			 *	Never set adb_state to idle here, or adb_start 
-			 *	won't be called again from send_request!
-			 *	(need to re-check other cases ...)
-			 */
-			case MAC_ADB_CUDA:
-				/* printk("device busy - fail\n"); */
-				restore_flags(flags);
-				/* a byte is coming in from the CUDA */
-				return;
-			case MAC_ADB_IISI:
-				printk("adb_start: device busy - fail\n");
-				retry_req = req;
-				restore_flags(flags);
-				return;
-			case MAC_ADB_II:
-				/*
-				 * if the interrupt handler set the need_poll
-				 * flag, it's hopefully a SRQ poll or re-Talk
-				 * so we try to send here anyway
-				 */
-				if (!need_poll) {
-					printk("device busy - retry %p state %d status %x!\n", 
-						req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
-					retry_req = req;
-					/* set ADB status here ? */
-					restore_flags(flags);
-					return;
-				} else {
-#if (ADBDEBUG & ADBDEBUG_START)
-					if (console_loglevel == 10)
-						printk("device busy - polling; state %d status %x!\n", 
-							adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
-#endif
-					need_poll = 0;
-					break;
-				}
-		}
-	}
-
-#if 0
-	/*
-	 * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here!
-	 * OTOH: setting ST_CMD in the interrupt routine would make the 
-	 * ADB contoller shift in before this routine starts shifting out ...
-	 */
-	if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE) 
-	{
-#if (ADBDEBUG & ADBDEBUG_STATE)
-		if (console_loglevel == 10)
-			printk("ADB bus not idle (%x), retry later!\n", 
-				via_read(via1, vBufB)&(ST_MASK|TREQ));
-#endif
-		retry_req = req;
-		restore_flags(flags);
-		return;							
-	}
-#endif
-
-	/*
-	 * Another retry pending? (sanity check)
-	 */
-	if (retry_req) {
-#if (ADBDEBUG & ADBDEBUG_RETRY)
-		if (console_loglevel == 10)
-		if (retry_req == req)
-			/* new requests are appended at tail of request queue */
-			printk("adb_start: retry %p pending ! \n", req);
-		else
-			/* poll requests are added to the head of queue */
-			printk("adb_start: retry %p pending, req %p (poll?) current! \n",
-				retry_req, req);
-#endif
-		retry_req = NULL;
-	}
-
-	/*
-	 * Seems OK, go for it!
-	 */
-	switch(macintosh_config->adb_type)
-	{
-		case MAC_ADB_CUDA:
-			/* store command byte (first byte is 'type' byte) */
-			command_byte = req->data[1];
-			/* set the shift register to shift out and send a byte */
-			via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); 
-			via_write(via1, vSR, req->data[0]);
-			via_write(via1, vBufB, via_read(via1, vBufB)&~TIP);
-			break;
-		case MAC_ADB_IISI:
-			/* store command byte (first byte is 'type' byte) */
-			command_byte = req->data[1];
-			/* set ADB state to 'active' */
-			via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
-			/* switch ACK off (in case it was left on) */
-			via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-			/* set the shift register to shift out and send a byte */
-			via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); 
-			via_write(via1, vSR, req->data[0]);
-			/* signal 'byte ready' */
-			via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-			break;
-		case MAC_ADB_II:
-			/* store command byte */
-			command_byte = req->data[0];
-			/* Output mode */
-			via_write(via1, vACR, via_read(via1, vACR)|SR_OUT);
-			/* Load data */
-			via_write(via1, vSR, req->data[0]);
-#ifdef USE_ORIG
-			/* Turn off TIP/TACK - this should tell the external logic to
-			   start the external shift clock */
-/*			via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/
-			via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK));
-#else
-			/* set ADB state to 'command' */
-			via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD);
-#endif
-			break;
-	}
-	adb_state = sent_first_byte;
-	data_index = 1;
-#if (ADBDEBUG & ADBDEBUG_START)
-	if (console_loglevel == 10)
-		printk("sent first byte of %d: %x, (%x %x) ... ", 
-			req->nbytes, req->data[0], adb_state, 
-			(via_read(via1, vBufB) & (ST_MASK|TREQ)) );
-#endif
-	restore_flags(flags);
-}
-
-/*
- * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs)
- */
-void adb_poll(void)
-{
-	unsigned char c;
-	unsigned long flags;
-	save_flags(flags);
-	cli();
-	c=via_read(via1, vIFR);
-#if (ADBDEBUG & ADBDEBUG_POLL)
-#ifdef DEBUG_ADB_INTS
-	if (console_loglevel == 10) {
-		printk("adb_poll: IFR %x state %x cl %d dat %d ", 
-			c, adb_state, nclock, ndata);
-		if (c & (SR_CLOCK|SR_DATA)) {
-			if (c & SR_CLOCK)
-				printk("adb clock event ");
-			if (c & SR_DATA)
-				printk("adb data event ");
-		}
-	}
-#else
-	if (console_loglevel == 10)
-		printk("adb_poll: IFR %x state %x ", 
-			c, adb_state);
-#endif
-	if (console_loglevel == 10)
-		printk("\r");
-#endif
-	if (c & SR_INT)
-	{
-#if (ADBDEBUG & ADBDEBUG_POLL)
-		if (console_loglevel == 10)
-			printk("adb_poll: adb interrupt event\n");
-#endif
-		adb_interrupt(0, 0, 0);
-	}
-	restore_flags(flags);
-}
-
-/*
- * Debugging gimmicks
- */
-void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs)
-{
-	nclock++;
-}
-
-void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs)
-{
-	ndata++;
-}
-
-/*
- * The notorious ADB interrupt handler - does all of the protocol handling, 
- * except for starting new send operations. Relies heavily on the ADB 
- * controller sending and receiving data, thereby generating SR interrupts
- * for us. This means there has to be always activity on the ADB bus, otherwise
- * the whole process dies and has to be re-kicked by sending TALK requests ...
- * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
- * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
- * a good choice; either on timeout or on a timer interrupt).
- *
- * The basic ADB state machine was left unchanged from the original MacII code
- * by Alan Cox, which was based on the CUDA driver for PowerMac. 
- * The syntax of the ADB status lines seems to be totally different on MacII, 
- * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
- * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start 
- * and end of a receive packet are signaled by asserting /IRQ on the interrupt
- * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on 
- * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the 
- * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB 
- * protocol with a logic analyzer!!)
- * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK
- * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for
- * receiving. No clue how timeouts are handled; SRQ seems to be sent as a 
- * separate packet. Quite a few changes have been made outside the handshake 
- * code, so I don't know if the CUDA code still behaves as before. 
- *
- * Note: As of 21/10/97, the MacII ADB part works including timeout detection
- * and retransmit (Talk to the last active device). Cleanup of code and 
- * testing of the CUDA functionality is required, though. 
- * Note2: As of 13/12/97, CUDA support is definitely broken ...
- * Note3: As of 21/12/97, CUDA works on a P475. What was broken? The assumption
- * that Q700 and Q800 use CUDA :-(
- *
- * 27/01/98: IIsi driver implemented (thanks to Robert Thompson for the 
- * initial bits). See adb_cuda_interrupts ...
- *
- * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG 
- * conditionals can be a start?)
- */
-void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
-{
-	int x, adbdir;
-	unsigned long flags;
-	struct adb_request *req;
-
-	last_status = status;
-
-	/* prevent races due to SCSI enabling ints */
-	save_flags(flags);
-	cli();
-
-	if (driver_running) {
-		restore_flags(flags);
-		return;
-	}
-
-	driver_running = 1;
-	
-#ifdef USE_ORIG
-	status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
-#else
-	if (macintosh_config->adb_type==MAC_ADB_CUDA)
-		status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
-	else
-		/* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */
-		status = (via_read(via1, vBufB) & (ST_MASK|TREQ)); 
-#endif
-	adbdir = (via_read(via1, vACR) & SR_OUT);
-#if (ADBDEBUG & ADBDEBUG_INT)
-	if (console_loglevel == 10)
-		printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n", 
-			adb_state, status, last_status, adbdir);
-#endif
-
-	switch (adb_state) 
-	{
-		case idle:
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-				/* CUDA has sent us the first byte of data - unsolicited */
-				if (status != TREQ)
-					printk("cuda: state=idle, status=%x\n", status);
-				x = via_read(via1, vSR); 
-				via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				udelay(150);
-				/* set SR to IN (??? no byte received else) */
-				via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); 
-		 		/* signal start of frame */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
-				/* read first byte */
-				x = via_read(via1, vSR);
-				first_byte = x;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_macIIsi : receiving unsol. packet: %x (%x %x) ", 
-						x, adb_state, status);
-#endif
-				/* ACK adb chip */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				udelay(150);
-		 		via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_II)
-			{
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-				if (status == TREQ && !adbdir) 
-					/* that's: not IRQ, idle, input -> weird */
-					printk("adb_macII: idle, status=%x dir=%x\n",
-						status, adbdir);
-#endif
-				x = via_read(via1, vSR);
-				first_byte = x;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_macII: receiving unsol. packet: %x (%x %x) ", 
-						x, adb_state, status);
-#endif
-				/* set ADB state = even for first data byte */
-				via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
-			}
-			adb_state = reading;
-			reply_ptr = cuda_rbuf;
-			reply_len = 0;
-			reading_reply = 0;
-			prefix_len = 0;
-			if (macintosh_config->adb_type==MAC_ADB_II) {
-				*reply_ptr++ = ADB_PACKET;
-				*reply_ptr++ = first_byte;
-				*reply_ptr++ = command_byte; /*first_byte;*/
-				reply_len    = 3;
-				prefix_len   = 3;
-			}
-			break;
-
-		case awaiting_reply:
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-				/* CUDA has sent us the first byte of data of a reply */
-				if (status != TREQ)
-					printk("cuda: state=awaiting_reply, status=%x\n", status);
-				x = via_read(via1, vSR); 
-				via_write(via1,vBufB, 
-					via_read(via1, vBufB)&~TIP);
-			} 
-			else if(macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				/* set SR to IN */
-				via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); 
-		 		/* signal start of frame */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
-				/* read first byte */
-				x = via_read(via1, vSR);
-				first_byte = x;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_macIIsi: reading reply: %x (%x %x) ",
-						x, adb_state, status);
-#endif
-#if 0
-				if( via_read(via1,vBufB) & TREQ)
-					ending = 1;
-				else
-					ending = 0;
-#endif
-				/* ACK adb chip */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				udelay(150);
-		 		via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_II) 
-			{
-				/* handshake etc. for II ?? */
-				x = via_read(via1, vSR);
-				first_byte = x;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_macII: reading reply: %x (%x %x) ",
-						x, adb_state, status);
-#endif
-				/* set ADB state = even for first data byte */
-				via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
-			}
-			adb_state = reading;			
-			reply_ptr = current_req->reply;
-			reading_reply = 1;
-			reply_len  = 0;
-			prefix_len = 0;
-			if (macintosh_config->adb_type==MAC_ADB_II) {
-				*reply_ptr++ = ADB_PACKET;
-				*reply_ptr++ = first_byte;
-				*reply_ptr++ = first_byte; /* should be command  byte */
-				reply_len    = 3;
-				prefix_len   = 3;
-			}
-			break;
-
-		case sent_first_byte:
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-			if (console_loglevel == 10)
-				printk(" sending: %x (%x %x) ",
-					current_req->data[1], adb_state, status);
-#endif
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-				if (status == TREQ + TIP + SR_OUT) 
-				{
-					/* collision */
-					via_write(via1, vACR,
-						via_read(via1, vACR)&~SR_OUT); 
-					x = via_read(via1, vSR); 
-					via_write(via1, vBufB,
-						via_read(via1,vBufB)|TIP|TACK); 
-					adb_state = idle;
-				}
-				else
-				{
-					/* assert status == TIP + SR_OUT */
-					if (status != TIP + SR_OUT)
-						printk("cuda: state=sent_first_byte status=%x\n", status);
-					via_write(via1,vSR,current_req->data[1]); 
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)^TACK); 
-					data_index = 2;
-					adb_state = sending;
-				}
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				/* switch ACK off */
-				via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-				if ( !(via_read(via1, vBufB) & TREQ) ) 
-				{
-					/* collision */
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-					if (console_loglevel == 10)
-						printk("adb_macIIsi: send collison, aborting!\n");
-#endif
-					/* set shift in */
-					via_write(via1, vACR,
-						via_read(via1, vACR)&~SR_OUT); 
-					/* clear SR int. */
-					x = via_read(via1, vSR); 
-					/* set ADB state to 'idle' */
-					via_write(via1, vBufB,
-						via_read(via1,vBufB) & ~(TIP|TACK)); 
-					adb_state = idle;
-				}
-				else
-				{
-					/* delay */
-					udelay(ADB_DELAY);
-					/* set the shift register to shift out and send a byte */
-#if 0
-					via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); 
-#endif
-					via_write(via1, vSR, current_req->data[1]);
-					/* signal 'byte ready' */
-					via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-					data_index=2;			
-					adb_state = sending;
-				}
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_II)
-			{
-				/* how to detect a collision here ?? */
-				/* maybe we're already done (Talk, or Poll)? */
-				if (data_index >= current_req->nbytes) 
-				{
-					/* assert it's a Talk ?? */
-					if ( (command_byte&0xc) != 0xc
-					    && console_loglevel == 10 )
-						printk("ADB: single byte command, no Talk: %x!\n", 
-							command_byte);
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-					if (console_loglevel == 10)
-						printk(" -> end (%d of %d) (%x %x)!\n",
-							data_index, current_req->nbytes, adb_state, status);
-#endif
-					current_req->sent = 1;
-					if (current_req->reply_expected) 
-					{
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-						if (console_loglevel == 10)
-							printk("ADB: reply expected on poll!\n");
-#endif
-						adb_state = awaiting_reply;
-						reading_reply = 0;
-					} else {
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-						if (console_loglevel == 10)
-							printk("ADB: no reply for poll, not calling done()!\n");
-#endif
-						req = current_req;
-						current_req = req->next;
-#if 0	/* XXX Not sure about that one ... probably better enabled */
-						if (req->done)
-							(*req->done)(req);
-#endif
-						adb_state = idle;
-						reading_reply = 0;
-					}
-					/* set to shift in */
-					via_write(via1, vACR,
-						via_read(via1, vACR) & ~SR_OUT);
-					x=via_read(via1, vSR);
-					/* set ADB state idle - might get SRQ */
-					via_write(via1, vBufB,
-						(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
-					break;
-				}
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-				if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT))
-					printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n", 
-					status, adbdir);
-#endif
-				/* SR already set to shift out; send byte */
-				via_write(via1, vSR, current_req->data[1]);
-				/* set state to ST_EVEN (first byte was: ST_CMD) */
-				via_write(via1, vBufB,
-					(via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
-				data_index=2;			
-				adb_state = sending;
-			}
-			break;
-
-		case sending:
-			req = current_req;
-			if (data_index >= req->nbytes) 
-			{
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-				if (console_loglevel == 10)
-					printk(" -> end (%d of %d) (%x %x)!\n",
-						data_index-1, req->nbytes, adb_state, status);
-#endif
-				/* end of packet */
-				if(macintosh_config->adb_type==MAC_ADB_CUDA)
-				{
-					via_write(via1, vACR,
-						via_read(via1, vACR)&~SR_OUT); 
-					x = via_read(via1, vSR); 
-					via_write(via1, vBufB,
-						via_read(via1,vBufB)|TACK|TIP); 
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_IISI)
-				{
-					/* XXX maybe clear ACK here ??? */
-					/* switch ACK off */
-					via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-					/* delay */
-					udelay(ADB_DELAY);
-					/* set the shift register to shift in */
-					via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); 
-					/* clear SR int. */
-					x = via_read(via1, vSR); 
-					/* set ADB state 'idle' (end of frame) */
-					via_write(via1, vBufB,
-						via_read(via1,vBufB) & ~(TACK|TIP)); 
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_II)
-				{
-					/*
-					 * XXX Not sure: maybe only switch to 
-					 * input mode on Talk ??
-					 */
-					/* set to shift in */
-					via_write(via1, vACR,
-						via_read(via1, vACR) & ~SR_OUT);
-					x=via_read(via1, vSR);
-					/* set ADB state idle - might get SRQ */
-					via_write(via1, vBufB,
-						(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
-				}
-				req->sent = 1;
-				if (req->reply_expected) 
-				{
-					/* 
-					 * maybe fake a reply here on Listen ?? 
-					 * Otherwise, a Listen hangs on success
-					 */
-					if ( macintosh_config->adb_type==MAC_ADB_II
-					     && ((req->data[0]&0xc) == 0xc) )
-						adb_state = awaiting_reply;
-					else if ( macintosh_config->adb_type != MAC_ADB_II
-						  && ( req->data[0]      == 0x0) 
-						  && ((req->data[1]&0xc) == 0xc) )
-						adb_state = awaiting_reply;
-					else {
-						/*
-						 * Reply expected, but none
-						 * possible -> fake reply.
-						 * Problem: sending next command
-						 * should probably be done 
-						 * without setting bus to 'idle'!
-						 * (except if no more commands)
-						 */
-#if (ADBDEBUG & ADBDEBUG_PROT)
-						printk("ADB: reply expected on Listen, faking reply\n");
-#endif
-						/* make it look weird */
-						/* XXX: return reply_len -1? */
-						/* XXX: fake ADB header? */
-						req->reply[0] = req->reply[1] = req->reply[2] = 0xFF;  
-						req->reply_len = 3;
-						req->got_reply = 1;
-						current_req = req->next;
-						if (req->done)
-							(*req->done)(req);
-						/* 
-						 * ready with this one, run 
-						 * next command or repeat last
-						 * Talk (=idle on II)
-						 */
-						/* set state to idle !! */
-						adb_state = idle;
-						if (current_req || retry_req)
-							adb_start();
-					}
-				}
-				else
-				{
-					current_req = req->next;
-					if (req->done)
-						(*req->done)(req);
-					/* not sure about this */
-					/* 
-					 * MS: Must set idle, no new request 
-					 *     started else !
-					 */
-					adb_state = idle;
-					/* 
-					 * requires setting ADB state to idle,
-					 * maybe read a byte ! (done above)
-					 */
-					if (current_req || retry_req)
-						adb_start();
-				}
-			}
-			else 
-			{
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-				if (console_loglevel == 10)
-					printk(" %x (%x %x) ",
-						req->data[data_index], adb_state, status);
-#endif
-				if(macintosh_config->adb_type==MAC_ADB_CUDA)
-				{
-					via_write(via1, vSR, req->data[data_index++]); 
-					via_write(via1, vBufB, 
-						via_read(via1, vBufB)^TACK); 
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_IISI)
-				{
-					/* switch ACK off */
-					via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-					/* delay */
-					udelay(ADB_DELAY);
-					/* XXX: need to check for collision?? */
-					/* set the shift register to shift out and send a byte */
-#if 0
-					via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); 
-#endif
-					via_write(via1, vSR, req->data[data_index++]);
-					/* signal 'byte ready' */
-					via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_II)
-				{
-					via_write(via1, vSR, req->data[data_index++]);
-					/* invert state bits, toggle ODD/EVEN */
-					x = via_read(via1, vBufB);
-					via_write(via1, vBufB,
-						(x&~ST_MASK)|~(x&ST_MASK));
-				}
-			}
-			break;
-
-		case reading:
-
-			/* timeout / SRQ handling for II hw */
-#ifdef POLL_ON_TIMEOUT
-			if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
-#else
-			if( (first_byte == 0xFF && (reply_len-prefix_len)==2 
-			     && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || 
-			    ((reply_len-prefix_len)==3 
-			     && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
-#endif
-			{
-				/*
-				 * possible timeout (in fact, most probably a 
-				 * timeout, since SRQ can't be signaled without
-				 * transfer on the bus).
-				 * The last three bytes seen were FF, together 
-				 * with the starting byte (in case we started
-				 * on 'idle' or 'awaiting_reply') this probably
-				 * makes four. So this is mostl likely #5!
-				 * The timeout signal is a pattern 1 0 1 0 0..
-				 * on /INT, meaning we missed it :-(
-				 */
-				x = via_read(via1, vSR);
-				if (x != 0xFF)
-					printk("ADB: mistaken timeout/SRQ!\n");
-
-				/* 
-				 * ADB status bits: either even or odd.
-				 * adb_state: need to set 'idle' here.
-				 * Maybe saner: set 'need_poll' or 
-				 * 'need_resend' here, fall through to 
-				 * read_done ??
-				 */
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk(" -> read aborted: %x (%x %x)!\n", 
-						x, adb_state, status);
-#endif
-
-#if 0	/* XXX leave status unchanged!! - need to check this again! */
-	/* XXX Only touch status on II !!! */
-				/* set ADB state to idle (required by adb_start()) */
-				via_write(via1, vBufB,
-					(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
-#endif
-
-				/*
-				 * What if the timeout happens on reading a 
-				 * reply ?? Assemble error reply and call 
-				 * current_request->done()? Keep request 
-				 * on queue?
-				 */
-
-				/* prevent 'busy' in adb_start() */
-				need_poll = 1;
-
-				/*
-				 * Timeout: /IRQ alternates high/low during 
-				 *          4 'FF' bytes (1 0 1 0 0...)
-				 *	    We're on byte 5, so we need one 
-				 *	    more backlog here (TBI) ....
-				 */
-				if ((status&TREQ) != (last_status&TREQ)) {
-#if (ADBDEBUG & ADBDEBUG_SRQ)
-					if (console_loglevel == 10)
-						printk("ADB: reply timeout, resending!\n");
-#endif
-					/*
-					 * first byte received should be the 
-					 * command byte timing out !!
-					 */
-					if (first_byte != 0xff)
-						command_byte = first_byte;
-
-					/*
-					 * compute target for retransmit: if
-					 * last_active is set, use that one, 
-					 * else use command_byte
-					 */
-					if (last_active == -1)
-						last_active = (command_byte&0xf0)>>4;
-					adb_state = idle;
-					/* resend if TALK, don't poll! */
-					if (current_req)
-						adb_start();
-					else
-					/* 
-					 * XXX: need to count the timeouts ?? 
-					 * restart last active TALK ??
-					 * If no current_req, reuse old one!
-					 */
-						adb_retransmit(last_active);
-
-				} else {
-				/*
-				 * SRQ: NetBSD suggests /IRQ is asserted!?
-				 */
-					if (status&TREQ)
-						printk("ADB: SRQ signature w/o /INT!\n");
-#if (ADBDEBUG & ADBDEBUG_SRQ)
-					if (console_loglevel == 10)
-						printk("ADB: empty SRQ packet!\n");
-#endif
-					/* Terminate the SRQ packet and poll */
-					adb_state = idle;
-					adb_queue_poll();
-				}
-				/*
-				 * Leave ADB status lines unchanged (means /IRQ
-				 * will still be low when entering adb_start!)
-				 */
-				break;
-			}
-			/* end timeout / SRQ handling for II hw. */
-			if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
-			{
-				/* SRQ tacked on data packet */
-				/* Check /IRQ here ?? */
-#if (ADBDEBUG & ADBDEBUG_SRQ)
-				if (console_loglevel == 10)
-					printk("\nADB: Packet with SRQ!\n");
-#endif
-				/* Terminate the packet (SRQ never ends) */
-				x = via_read(via1, vSR);
-				adb_state = read_done;
-				reply_len -= 3;
-				reply_ptr -= 3;
-				need_poll = 1;
-				/* need to continue; next byte not seen else */
-				/* 
-				 * XXX: not at all sure here; maybe need to 
-				 * send away the reply and poll immediately?
-				 */
-			} else {
-				/* Sanity check */
-				if(reply_len>15)
-					reply_len=0;
-				/* read byte */
-				*reply_ptr = via_read(via1, vSR); 
-				x = *reply_ptr;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk(" %x (%x %x) ", 
-						*reply_ptr, adb_state, status);
-#endif
-				reply_ptr++;
-				reply_len++;
-			}
-			/* The usual handshake ... */
-			if (macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-				if (status == TIP)
-				{
-					/* that's all folks */
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)|TACK|TIP); 
-					adb_state = read_done;
-				}
-				else 
-				{
-					/* assert status == TIP | TREQ */
-					if (status != TIP + TREQ)
-						printk("cuda: state=reading status=%x\n", status);
-					via_write(via1, vBufB, 
-						via_read(via1, vBufB)^TACK); 
-				}
-			}
-			else if (macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				/* ACK adb chip (maybe check for end first?) */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				udelay(150);
-		 		via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-				/* end of frame?? */
-				if (status & TREQ)
-				{
-#if (ADBDEBUG & ADBDEBUG_READ)
-					if (console_loglevel == 10)
-						printk("adb_IIsi: end of frame!\n");
-#endif
-					/* that's all folks */
-					via_write(via1, vBufB,
-						via_read(via1, vBufB) & ~(TACK|TIP)); 
-					adb_state = read_done;
-					/* maybe process read_done here?? Handshake anyway?? */
-				}
-			}
-			else if (macintosh_config->adb_type==MAC_ADB_II)
-			{
-				/*
-				 * NetBSD hints that the next to last byte 
-				 * is sent with IRQ !! 
-				 * Guido found out it's the last one (0x0),
-				 * but IRQ should be asserted already.
-				 * Problem with timeout detection: First
-				 * transition to /IRQ might be second 
-				 * byte of timeout packet! 
-				 * Timeouts are signaled by 4x FF.
-				 */
-				if(!(status&TREQ) && x == 0x00) /* != 0xFF */
-				{
-#if (ADBDEBUG & ADBDEBUG_READ)
-					if (console_loglevel == 10)
-						printk(" -> read done!\n");
-#endif
-#if 0		/* XXX: we take one more byte (why?), so handshake! */
-					/* set ADB state to idle */
-					via_write(via1, vBufB,
-						(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
-#else
-					/* invert state bits, toggle ODD/EVEN */
-					x = via_read(via1, vBufB);
-					via_write(via1, vBufB,
-						(x&~ST_MASK)|~(x&ST_MASK));
-#endif
-					/* adjust packet length */
-					reply_len--;
-					reply_ptr--;
-					adb_state = read_done;
-				}
-				else
-				{
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-					if(status!=TIP+TREQ)
-						printk("macII_adb: state=reading status=%x\n", status);
-#endif
-					/* not caught: ST_CMD */
-					/* required for re-entry 'reading'! */
-					if ((status&ST_MASK) == ST_IDLE) {
-						/* (in)sanity check - set even */
-						via_write(via1, vBufB,
-							(via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
-					} else {
-						/* invert state bits, toggle ODD/EVEN */
-						x = via_read(via1, vBufB);
-						via_write(via1, vBufB,
-							(x&~ST_MASK)|~(x&ST_MASK));
-					}
-				}
-			}
-			break;
-
-		case read_done:
-			x = via_read(via1, vSR); 
-#if (ADBDEBUG & ADBDEBUG_READ)
-			if (console_loglevel == 10)
-				printk("ADB: read done: %x (%x %x)!\n", 
-					x, adb_state, status);
-#endif
-			if (reading_reply) 
-			{
-				req = current_req;
-				req->reply_len = reply_ptr - req->reply;
-				req->got_reply = 1;
-				current_req = req->next;
-				if (req->done)
-					(*req->done)(req);
-			}
-			else
-			{
-				adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
-			}
-
-			/*
-			 * remember this device ID; it's the latest we got a 
-			 * reply from!
-			 */
-			last_reply = command_byte;
-			last_active = (command_byte&0xf0)>>4;
-
-			/*
-			 * Assert status = ST_IDLE ??
-			 */
-			/* 
-			 * SRQ seen before, initiate poll now
-			 */
-			if (need_poll) {
-#if (ADBDEBUG & ADBDEBUG_POLL)
-				if (console_loglevel == 10)
-					printk("ADB: initiate poll!\n");
-#endif
-				adb_state = idle;
-				/*
-				 * set ADB status bits?? (unchanged above!)
-				 */
-				adb_queue_poll();
-				need_poll = 0;
-				/* hope this is ok; queue_poll runs adb_start */
-				break;
-			}
-
-			/*
-			 * /IRQ seen, so the ADB controller has data for us
-			 */
-			if (!(status&TREQ)) 
-			{
-				/* set ADB state to idle */
-				via_write(via1, vBufB,
-					(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); 
-
-				adb_state = reading;
-				reply_ptr = cuda_rbuf;
-				reply_len = 0;
-				prefix_len = 0;
-				if (macintosh_config->adb_type==MAC_ADB_II) {
-					*reply_ptr++ = ADB_PACKET;
-					*reply_ptr++ = command_byte;
-					reply_len    = 2;
-					prefix_len   = 2;
-				}
-				reading_reply = 0;
-			}
-			else 
-			{
-				/*
-				 * no IRQ, send next packet or wait
-				 */
-				adb_state = idle;
-				if (current_req)
-					adb_start();
-				else
-					adb_retransmit(last_active);
-			}
-			break;
-
-		default:
-#if (ADBDEBUG & ADBDEBUG_STATE)
-			printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
-#endif
-	}
-	/* reset mutex and interrupts */
-	driver_running = 0;
-	restore_flags(flags);
-}
-
-/*
- * Restart of CUDA support: please modify this interrupt handler while 
- * working at the Quadra etc. ADB driver. We can try to merge them later, or
- * remove the CUDA stuff from the MacII handler
- *
- * MSch 27/01/98: Implemented IIsi driver based on initial code by Robert 
- * Thompson and hints from the NetBSD driver. CUDA and IIsi seem more closely
- * related than to the MacII code, so merging all three might be a bad
- * idea.
- */
-
-void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
-{
-	int x, status;
-	struct adb_request *req;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
-
-	if(macintosh_config->adb_type==MAC_ADB_CUDA)
-		status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
-	else
-		status = via_read(via1, vBufB) & (TIP|TREQ);
-
-#if (ADBDEBUG & ADBDEBUG_INT)
-	if (console_loglevel == 10)
-		printk("adb_interrupt: state=%d status=%x\n", adb_state, status);
-#endif
-
-	switch (adb_state) 
-	{
-		case idle:
-			first_byte = 0;
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-				/* CUDA has sent us the first byte of data - unsolicited */
-				if (status != TREQ)
-					printk("cuda: state=idle, status=%x want=%x\n", 
-						status, TREQ);
-#endif
-				x = via_read(via1, vSR); 
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_cuda: receiving unsol. packet: %x (%x %x) ", 
-						x, adb_state, status);
-#endif
-				via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				udelay(150);
-				/* set SR to IN */
-				via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); 
-		 		/* signal start of frame */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
-				/* read first byte */
-				x = via_read(via1, vSR);
-				first_byte = x;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_IIsi : receiving unsol. packet: %x (%x %x) ", 
-						x, adb_state, status);
-#endif
-				/* ACK adb chip */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				udelay(150);
-		 		via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_II)
-			{
-				if (status != TREQ)
-					printk("adb_macII: state=idle status=%x want=%x\n",
-						status, TREQ);
-				x = via_read(via1, vSR);
-				via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
-			}
-			adb_state = reading;
-			reply_ptr = cuda_rbuf;
-			reply_len = 0;
-			reading_reply = 0;
-			break;
-
-		case awaiting_reply:
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-				/* CUDA has sent us the first byte of data of a reply */
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-				if (status != TREQ)
-					printk("cuda: state=awaiting_reply, status=%x want=%x\n", 
-						status, TREQ);
-#endif
-				x = via_read(via1, vSR); 
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_cuda: reading reply: %x (%x %x) ",
-						x, adb_state, status);
-#endif
-				via_write(via1,vBufB, 
-					via_read(via1, vBufB)&~TIP);
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				/* udelay(150);*/
-				/* set SR to IN */
-				via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT); 
-		 		/* signal start of frame */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
-				/* read first byte */
-				x = via_read(via1, vSR);
-				first_byte = x;
-#if (ADBDEBUG & ADBDEBUG_READ)
-				if (console_loglevel == 10)
-					printk("adb_IIsi: reading reply: %x (%x %x) ",
-						x, adb_state, status);
-#endif
-#if 0
-				if( via_read(via1,vBufB) & TREQ)
-					ending = 1;
-				else
-					ending = 0;
-#endif
-				/* ACK adb chip */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				udelay(150);
-		 		via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-			}
-			adb_state = reading;			
-			reply_ptr = current_req->reply;
-			reading_reply = 1;
-			reply_len = 0;
-			break;
-
-		case sent_first_byte:
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-				if (console_loglevel == 10)
-					printk(" sending: %x (%x %x) ",
-						current_req->data[1], adb_state, status);
-#endif
-				if (status == TREQ + TIP + SR_OUT) 
-				{
-					/* collision */
-					if (console_loglevel == 10)
-						printk("adb_cuda: send collision!\n");
-					via_write(via1, vACR,
-						via_read(via1, vACR)&~SR_OUT); 
-					x = via_read(via1, vSR); 
-					via_write(via1, vBufB,
-						via_read(via1,vBufB)|TIP|TACK); 
-					adb_state = idle;
-				}
-				else
-				{
-					/* assert status == TIP + SR_OUT */
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-					if (status != TIP + SR_OUT)
-						printk("adb_cuda: state=sent_first_byte status=%x want=%x\n", 
-							status, TIP + SR_OUT);
-#endif
-					via_write(via1,vSR,current_req->data[1]); 
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)^TACK); 
-					data_index = 2;
-					adb_state = sending;
-				}
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				/* switch ACK off */
-				via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-				if ( !(via_read(via1, vBufB) & TREQ) ) 
-				{
-					/* collision */
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-					if (console_loglevel == 10)
-						printk("adb_macIIsi: send collison, aborting!\n");
-#endif
-					/* set shift in */
-					via_write(via1, vACR,
-						via_read(via1, vACR)&~SR_OUT); 
-					/* clear SR int. */
-					x = via_read(via1, vSR); 
-					/* set ADB state to 'idle' */
-					via_write(via1, vBufB,
-						via_read(via1,vBufB) & ~(TIP|TACK)); 
-					adb_state = idle;
-				}
-				else
-				{
-					/* delay */
-					udelay(ADB_DELAY);
-					/* set the shift register to shift out and send a byte */
-#if 0
-					via_write(via1, vACR, via_read(via1, vACR) | SR_OUT); 
-#endif
-					via_write(via1, vSR, current_req->data[1]);
-					/* signal 'byte ready' */
-					via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-					data_index=2;			
-					adb_state = sending;
-				}
-			}
-			else if(macintosh_config->adb_type==MAC_ADB_II)
-			{
-				if(status!=TIP+SR_OUT)
-					printk("adb_macII: state=send_first_byte status=%x want=%x\n", 
-						status, TIP+SR_OUT);
-				via_write(via1, vSR, current_req->data[1]);
-				via_write(via1, vBufB,
-					via_read(via1, vBufB)^TACK);
-				data_index=2;			
-				adb_state = sending;
-			}
-			break;
-
-		case sending:
-			req = current_req;
-			if (data_index >= req->nbytes) 
-			{
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-				if (console_loglevel == 10)
-					printk(" -> end (%d of %d) (%x %x)!\n",
-						data_index-1, req->nbytes, adb_state, status);
-#endif
-				if(macintosh_config->adb_type==MAC_ADB_CUDA)
-				{
-					via_write(via1, vACR,
-						via_read(via1, vACR)&~SR_OUT); 
-					x = via_read(via1, vSR); 
-					via_write(via1, vBufB,
-						via_read(via1,vBufB)|TACK|TIP); 
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_IISI)
-				{
-					/* XXX maybe clear ACK here ??? */
-					/* switch ACK off */
-					via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-					/* delay */
-					udelay(ADB_DELAY);
-					/* set the shift register to shift in */
-					via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); 
-					/* clear SR int. */
-					x = via_read(via1, vSR); 
-					/* set ADB state 'idle' (end of frame) */
-					via_write(via1, vBufB,
-						via_read(via1,vBufB) & ~(TACK|TIP)); 
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_II)
-				{
-					via_write(via1, vACR,
-						via_read(via1, vACR) & ~SR_OUT);
-					x=via_read(via1, vSR);
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)|TACK|TIP);
-				}
-				req->sent = 1;
-				if (req->reply_expected) 
-				{
-					/* 
-					 * maybe fake a reply here on Listen ?? 
-					 * Otherwise, a Listen hangs on success
-					 * CUDA+IIsi: only ADB Talk considered
-					 * RTC/PRAM read (0x1 0x3) to follow.
-					 */
-					if ( (req->data[0] == 0x0) && ((req->data[1]&0xc) == 0xc) )
-						adb_state = awaiting_reply;
-					else {
-						/*
-						 * Reply expected, but none
-						 * possible -> fake reply.
-						 */
-#if (ADBDEBUG & ADBDEBUG_PROT)
-						printk("ADB: reply expected on Listen, faking reply\n");
-#endif
-						/* make it look weird */
-						/* XXX: return reply_len -1? */
-						/* XXX: fake ADB header? */
-						req->reply[0] = req->reply[1] = req->reply[2] = 0xFF;  
-						req->reply_len = 3;
-						req->got_reply = 1;
-						current_req = req->next;
-						if (req->done)
-							(*req->done)(req);
-						/* 
-						 * ready with this one, run 
-						 * next command !
-						 */
-						/* set state to idle !! */
-						adb_state = idle;
-						if (current_req || retry_req)
-							adb_start();
-					}
-				}
-				else
-				{
-					current_req = req->next;
-					if (req->done)
-						(*req->done)(req);
-					/* not sure about this */
-					adb_state = idle;
-					adb_start();
-				}
-			}
-			else 
-			{
-#if (ADBDEBUG & ADBDEBUG_WRITE)
-				if (console_loglevel == 10)
-					printk(" %x (%x %x) ",
-						req->data[data_index], adb_state, status);
-#endif
-				if(macintosh_config->adb_type==MAC_ADB_CUDA)
-				{
-					via_write(via1, vSR, req->data[data_index++]); 
-					via_write(via1, vBufB, 
-						via_read(via1, vBufB)^TACK); 
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_IISI)
-				{
-					/* switch ACK off */
-					via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-					/* delay */
-					udelay(ADB_DELAY);
-					/* XXX: need to check for collision?? */
-					/* set the shift register to shift out and send a byte */
-#if 0
-					via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); 
-#endif
-					via_write(via1, vSR, req->data[data_index++]);
-					/* signal 'byte ready' */
-					via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				}
-				else if(macintosh_config->adb_type==MAC_ADB_II)
-				{
-					via_write(via1, vSR, req->data[data_index++]);
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)^TACK);
-				}
-			}
-			break;
-
-		case reading:
-			if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
-			{
-				/* Terminate the SRQ packet */
-#if (ADBDEBUG & ADBDEBUG_SRQ)
-				if (console_loglevel == 10)
-					printk("adb: Got an SRQ\n");
-#endif
-				adb_state = idle;
-				adb_queue_poll();
-				break;
-			}
-			/* Sanity check - botched in orig. code! */
-			if(reply_len>15) {
-				printk("adb_cuda: reply buffer overrun!\n");
-				/* wrap buffer */
-				reply_len=0;
-				if (reading_reply)
-					reply_ptr = current_req->reply;
-				else
-					reply_ptr = cuda_rbuf;
-			}
-			*reply_ptr = via_read(via1, vSR); 
-#if (ADBDEBUG & ADBDEBUG_READ)
-			if (console_loglevel == 10)
-				printk(" %x (%x %x) ", 
-					*reply_ptr, adb_state, status);
-#endif
-			reply_ptr++;
-			reply_len++;
-			if(macintosh_config->adb_type==MAC_ADB_CUDA)
-			{
-				if (status == TIP)
-				{
-					/* that's all folks */
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)|TACK|TIP); 
-					adb_state = read_done;
-				}
-				else 
-				{
-					/* assert status == TIP | TREQ */
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-					if (status != TIP + TREQ)
-						printk("cuda: state=reading status=%x want=%x\n", 
-							status, TIP + TREQ);
-#endif
-					via_write(via1, vBufB, 
-						via_read(via1, vBufB)^TACK); 
-				}
-			}
-			else if (macintosh_config->adb_type==MAC_ADB_IISI)
-			{
-				/* ACK adb chip (maybe check for end first?) */
-		 		via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
-				udelay(150);
-		 		via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
-				/* end of frame?? */
-				if (status & TREQ)
-				{
-#if (ADBDEBUG & ADBDEBUG_READ)
-					if (console_loglevel == 10)
-						printk("adb_IIsi: end of frame!\n");
-#endif
-					/* that's all folks */
-					via_write(via1, vBufB,
-						via_read(via1, vBufB) & ~(TACK|TIP)); 
-					adb_state = read_done;
-					/* XXX maybe process read_done here?? 
-					   Handshake anyway?? */
-				}
-			}
-			if(macintosh_config->adb_type==MAC_ADB_II)
-			{
-				if( status == TIP)
-				{
-					via_write(via1, vBufB,
-						via_read(via1, vBufB)|TACK|TIP);
-					adb_state = read_done;
-				}
-				else
-				{
-#if (ADBDEBUG & ADBDEBUG_STATUS)
-					if(status!=TIP+TREQ)
-						printk("macII_adb: state=reading status=%x\n", status);
-#endif
-					via_write(via1, vBufB, 
-						via_read(via1, vBufB)^TACK);
-				}
-			}
-			/* fall through for IIsi on end of frame */
-			if (macintosh_config->adb_type != MAC_ADB_IISI
-			    || adb_state != read_done)
-				break;
-
-		case read_done:
-			x = via_read(via1, vSR); 
-#if (ADBDEBUG & ADBDEBUG_READ)
-			if (console_loglevel == 10)
-				printk("adb: read done: %x (%x %x)!\n", 
-					x, adb_state, status);
-#endif
-			if (reading_reply) 
-			{
-				req = current_req;
-				req->reply_len = reply_ptr - req->reply;
-				req->got_reply = 1;
-				current_req = req->next;
-				if (req->done)
-					(*req->done)(req);
-			}
-			else
-			{
-				adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
-			}
-
-			if (macintosh_config->adb_type==MAC_ADB_CUDA 
-			      &&   status & TREQ) 
-			{
-				via_write(via1, vBufB,
-					via_read(via1, vBufB)&~TIP); 
-				adb_state = reading;
-				reply_ptr = cuda_rbuf;
-				reading_reply = 0;
-			}
-			else if  (macintosh_config->adb_type==MAC_ADB_IISI
-			      && !(status & TREQ))
-			{
-				udelay(150);
-				via_write(via1, vBufB,
-					via_read(via1, vBufB) | TIP); 
-				adb_state = reading;
-				reply_ptr = cuda_rbuf;
-				reading_reply = 0;
-			}
-			else 
-			{
-				adb_state = idle;
-				adb_start();
-			}
-			break;
-
-		default:
-			printk("adb_cuda_interrupt: unknown adb_state %d?\n", adb_state);
-	}
-
-	restore_flags(flags);
-
-}
-
-/*
- *	The 'reply delivery' routine; determines which device sent the 
- *	request and calls the appropriate handler. 
- *	Reply data are expected in CUDA format (again, argh...) so we need
- *	to fake this in the interrupt handler for MacII.
- *	Only one handler per device ID is currently possible.
- *	XXX: is the ID field here representing the default or real ID?
- */
-static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs)
-{
-	int i, id;
-
-	switch (buf[0]) 
-	{
-		case ADB_PACKET:
-			/* what's in buf[1] ?? */
-			id = buf[2] >> 4;
-#if 0
-			xmon_printf("adb packet: ");
-			for (i = 0; i < nb; ++i)
-				xmon_printf(" %x", buf[i]);
-			xmon_printf(", id = %d\n", id);
-#endif
-#if (ADBDEBUG & ADBDEBUG_INPUT)
-			if (console_loglevel == 10) {
-				printk("adb_input: adb packet ");
-				for (i = 0; i < nb; ++i)
-					printk(" %x", buf[i]);
-				printk(", id = %d\n", id);
-			}
-#endif
-			if (adb_handler[id].handler != 0) 
-			{
-				(*adb_handler[id].handler)(buf, nb, regs);
-			}
-			break;
-
-		default:
-#if (ADBDEBUG & ADBDEBUG_INPUT)
-			if (console_loglevel == 10) {
-				printk("adb_input: data from via (%d bytes):", nb);
-				for (i = 0; i < nb; ++i)
-					printk(" %.2x", buf[i]);
-				printk("\n");
-			}
-#endif
-	}
-}
-
-/* Ultimately this should return the number of devices with
-   the given default id. */
-
-int adb_register(int default_id,
-	     void (*handler)(unsigned char *, int, struct pt_regs *))
-{
-	if (adb_handler[default_id].handler != 0)
-		panic("Two handlers for ADB device %d\n", default_id);
-	adb_handler[default_id].handler = handler;
-	return 1;
-}
-
-/*
- * /dev/adb device driver.
- */
-
-#define ADB_MAJOR	56	/* major number for /dev/adb */
-
-#define ADB_MAX_MINOR	64	/* range of ADB minors */
-#define ADB_TYPE_SHIFT	4	/* # bits for device ID/type in subdevices */
-
-#define ADB_TYPE_RAW	0	/* raw device; unbuffered */
-#define ADB_TYPE_BUFF	1	/* raw device; buffered */
-#define ADB_TYPE_COOKED	2	/* 'cooked' device */
-
-
-extern void adbdev_init(void);
-
-struct adbdev_state {
-	struct adb_request req;
-};
-
-static DECLARE_WAIT_QUEUE_HEAD(adb_wait);
-
-static int adb_wait_reply(struct adbdev_state *state, struct file *file)
-{
-	int ret = 0;
-	DECLARE_WAITQUEUE(wait,current);
-
-	__set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&adb_wait, &wait);
-
-	while (!state->req.got_reply) {
-		if (file->f_flags & O_NONBLOCK) {
-			ret = -EAGAIN;
-			break;
-		}
-		if (signal_pending(current)) {
-			ret = -ERESTARTSYS;
-			break;
-		}
-		schedule();
-	}
-
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&adb_wait, &wait);
-
-	return ret;
-}
-
-static void adb_write_done(struct adb_request *req)
-{
-	if (!req->got_reply) {
-		req->reply_len = 0;
-		req->got_reply = 1;
-	}
-	wake_up_interruptible(&adb_wait);
-}
-
-struct file_operations *adb_raw[16];
-struct file_operations *adb_buffered[16];
-struct file_operations *adb_cooked[16];
-
-static int adb_open(struct inode *inode, struct file *file)
-{
-	int adb_type, adb_subtype;
-	struct adbdev_state *state;
-
-	if (MINOR(inode->i_rdev) > ADB_MAX_MINOR)
-		return -ENXIO;
-
-	switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) {
-		case ADB_TYPE_RAW:
-			/* see code below */
-			break;
-		case ADB_TYPE_BUFF:
-			/* TBI */
-			return -ENXIO;
-		case ADB_TYPE_COOKED:
-			/* subtypes such as kbd, mouse, ... */
-			adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT;
-			if ((file->f_op = adb_cooked[adb_subtype]))
-				return file->f_op->open(inode,file);
-			else
-				return -ENODEV;
-	}
-
-	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
-	if (state == 0)
-		return -ENOMEM;
-	file->private_data = state;
-	state->req.reply_expected = 0;
-	return 0;
-}
-
-static void adb_release(struct inode *inode, struct file *file)
-{
-	struct adbdev_state *state = file->private_data;
-
-	if (state) {
-		file->private_data = NULL;
-		if (state->req.reply_expected && !state->req.got_reply)
-			if (adb_wait_reply(state, file))
-				return;
-		kfree(state);
-	}
-	return;
-}
-
-static int adb_lseek(struct inode *inode, struct file *file, 
-		     off_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-static int adb_read(struct inode *inode, struct file *file,
-		     char *buf, int count)
-{
-	int ret;
-	struct adbdev_state *state = file->private_data;
-
-	if (count < 2)
-		return -EINVAL;
-	if (count > sizeof(state->req.reply))
-		count = sizeof(state->req.reply);
-	ret = verify_area(VERIFY_WRITE, buf, count);
-	if (ret)
-		return ret;
-
-	if (!state->req.reply_expected)
-		return 0;
-
-	ret = adb_wait_reply(state, file);
-	if (ret)
-		return ret;
-
-	state->req.reply_expected = 0;
-	ret = state->req.reply_len;
-	copy_to_user(buf, state->req.reply, ret);
-
-	return ret;
-}
-
-static int adb_write(struct inode *inode, struct file *file,
-		      const char *buf, int count)
-{
-	int ret, i;
-	struct adbdev_state *state = file->private_data;
-
-	if (count < 2 || count > sizeof(state->req.data))
-		return -EINVAL;
-	ret = verify_area(VERIFY_READ, buf, count);
-	if (ret)
-		return ret;
-
-	if (state->req.reply_expected && !state->req.got_reply) {
-		/* A previous request is still being processed.
-		   Wait for it to finish. */
-		ret = adb_wait_reply(state, file);
-		if (ret)
-			return ret;
-	}
-
-	state->req.nbytes = count;
-	state->req.done = adb_write_done;
-	state->req.got_reply = 0;
-	copy_from_user(state->req.data, buf, count);
-#if 0
-	switch (adb_hardware) {
-	case ADB_NONE:
-		return -ENXIO;
-	case ADB_VIACUDA:
-		state->req.reply_expected = 1;
-		cuda_send_request(&state->req);
-		break;
-	default:
-#endif
-		if (state->req.data[0] != ADB_PACKET)
-			return -EINVAL;
-		for (i = 1; i < state->req.nbytes; ++i)
-			state->req.data[i] = state->req.data[i+1];
-		state->req.reply_expected =
-			((state->req.data[0] & 0xc) == 0xc);
-		adb_send_request(&state->req);
-#if 0
-		break;
-	}
-#endif
-
-	return count;
-}
-
-static struct file_operations adb_fops = {
-	llseek:		adb_lseek,
-	read:		adb_read,
-	write:		adb_write,
-	open:		adb_open,
-	release:	adb_release,
-};
-
-int adbdev_register(int subtype, struct file_operations *fops)
-{
-	if (subtype < 0 || subtype > 15)
-		return -EINVAL;
-	if (adb_cooked[subtype])
-		return -EBUSY;
-	adb_cooked[subtype] = fops;
-	return 0;
-}
-
-int adbdev_unregister(int subtype)
-{
-	if (subtype < 0 || subtype > 15)
-		return -EINVAL;
-	if (!adb_cooked[subtype])
-		return -ENODEV;
-	adb_cooked[subtype] = NULL;
-	return 0;
-}
-
-void adbdev_init()
-{
-	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
-		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
-}
-
-
-#if 0 /* old ADB device */
-
-/*
- * Here are the file operations we export for /dev/adb.
- */
-
-#define ADB_MINOR	140	/* /dev/adb is c 10 140 */
-
-extern void adbdev_inits(void);
-
-struct adbdev_state {
-	struct adb_request req;
-};
-
-static DECLARE_WAIT_QUEUE_HEAD(adb_wait);
-
-static int adb_wait_reply(struct adbdev_state *state, struct file *file)
-{
-	int ret = 0;
-	DECLARE_WAITQUEUE(wait, current);
-
-#if (ADBDEBUG & ADBDEBUG_DEVICE)
-	printk("ADB request: wait_reply (blocking ... \n");
-#endif
-
-	__set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&adb_wait, &wait);
-
-	while (!state->req.got_reply) {
-		if (file->f_flags & O_NONBLOCK) {
-			ret = -EAGAIN;
-			break;
-		}
-		if (signal_pending(current)) {
-			ret = -ERESTARTSYS;
-			break;
-		}
-		schedule();
-	}
-
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&adb_wait, &wait);
-
-	return ret;
-}
-
-static void adb_write_done(struct adb_request *req)
-{
-	if (!req->got_reply) {
-		req->reply_len = 0;
-		req->got_reply = 1;
-	}
-	wake_up_interruptible(&adb_wait);
-}
-
-static int adb_open(struct inode *inode, struct file *file)
-{
-	struct adbdev_state *state;
-
-	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
-	if (state == 0)
-		return -ENOMEM;
-	file->private_data = state;
-	state->req.reply_expected = 0;
-	return 0;
-}
-
-static void adb_release(struct inode *inode, struct file *file)
-{
-	struct adbdev_state *state = file->private_data;
-
-	if (state) {
-		file->private_data = NULL;
-		if (state->req.reply_expected && !state->req.got_reply)
-			if (adb_wait_reply(state, file))
-				return;
-		kfree(state);
-	}
-	return;
-}
-
-static int adb_lseek(struct inode *inode, struct file *file,
-		     off_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-static int adb_read(struct inode *inode, struct file *file,
-		    char *buf, int count)
-{
-	int ret;
-	struct adbdev_state *state = file->private_data;
-
-	if (count < 2)
-		return -EINVAL;
-	if (count > sizeof(state->req.reply))
-		count = sizeof(state->req.reply);
-	ret = verify_area(VERIFY_WRITE, buf, count);
-	if (ret)
-		return ret;
-
-	if (!state->req.reply_expected)
-		return 0;
-
-	ret = adb_wait_reply(state, file);
-	if (ret)
-		return ret;
-
-	ret = state->req.reply_len;
-	memcpy_tofs(buf, state->req.reply, ret);
-	state->req.reply_expected = 0;
-
-	return ret;
-}
-
-static int adb_write(struct inode *inode, struct file *file,
-		     const char *buf, int count)
-{
-	int ret;
-	struct adbdev_state *state = file->private_data;
-
-	if (count < 2 || count > sizeof(state->req.data))
-		return -EINVAL;
-	ret = verify_area(VERIFY_READ, buf, count);
-	if (ret)
-		return ret;
-
-	if (state->req.reply_expected && !state->req.got_reply) {
-		/* A previous request is still being processed.
-		   Wait for it to finish. */
-		ret = adb_wait_reply(state, file);
-		if (ret)
-			return ret;
-	}
-
-	state->req.nbytes = count;
-	state->req.done = adb_write_done;
-	memcpy_fromfs(state->req.data, buf, count);
-	state->req.reply_expected = 1;
-	state->req.got_reply = 0;
-	adb_send_request(&state->req);
-
-	return count;
-}
-
-static struct file_operations adb_fops = {
-	llseek:		adb_lseek,
-	read:		adb_read,
-	write:		adb_write,
-	open:		adb_open,
-	release:	adb_release,
-};
-
-static struct miscdevice adb_dev = {
-	ADB_MINOR,
-	"adb",
-	&adb_fops
-};
-
-void adbdev_init(void)
-{
-	misc_register(&adb_dev);
-}
-
-#endif /* old ADB device */
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/baboon.c linux/arch/m68k/mac/baboon.c
--- v2.3.44/linux/arch/m68k/mac/baboon.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/baboon.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,125 @@
+/*
+ * Baboon Custom IC Managment
+ *
+ * The Baboon custom IC controls the IDE, PCMCIA and media bay on the
+ * PowerBook 190. It multiplexes multiple interrupt sources onto the
+ * Nubus slot $C interrupt.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/traps.h>
+#include <asm/bootinfo.h> 
+#include <asm/macintosh.h> 
+#include <asm/macints.h> 
+#include <asm/mac_baboon.h>
+
+/* #define DEBUG_BABOON /**/
+/* #define DEBUG_IRQS /**/
+
+int baboon_present,baboon_active;
+volatile struct baboon *baboon;
+
+void baboon_irq(int, void *, struct pt_regs *);
+
+extern int console_loglevel;
+
+extern int macide_ack_intr(ide_hwif_t *);
+
+/*
+ * Baboon initialization.
+ */
+
+void __init baboon_init(void)
+{
+	if (macintosh_config->ident != MAC_MODEL_PB190) {
+		baboon = NULL;
+		baboon_present = 0;
+		return;
+	}
+
+	baboon = (struct baboon *) BABOON_BASE;
+	baboon_present = 1;
+	baboon_active = 0;
+
+	printk("Baboon detected at %p\n", baboon);
+}
+
+/*
+ * Register the Baboon interrupt dispatcher on nubus slot $C.
+ */
+
+void __init baboon_register_interrupts(void)
+{
+	request_irq(IRQ_NUBUS_C, baboon_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+		    "baboon", (void *) baboon);
+}
+
+/*
+ * Baboon interrupt handler. This works a lot like a VIA.
+ */
+
+void baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int irq_bit,i;
+	unsigned char events;
+
+#ifdef DEBUG_IRQS
+	printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n",
+		(uint) baboon->mb_control, (uint) baboon->mb_ifr,
+		(uint) baboon->mb_status,  baboon_active);
+#endif
+
+	if (!(events = baboon->mb_ifr & 0x07)) return;
+
+	for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
+	        if (events & irq_bit/* & baboon_active*/) {
+			baboon_active &= ~irq_bit;
+			mac_do_irq_list(IRQ_BABOON_0 + i, regs);
+			baboon_active |= irq_bit;
+			baboon->mb_ifr &= ~irq_bit;
+		}
+	}
+#if 0
+	if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
+	/* for now we need to smash all interrupts */
+	baboon->mb_ifr &= ~events;
+#endif
+}
+
+void baboon_irq_enable(int irq) {
+	int irq_idx	= IRQ_IDX(irq);
+
+#ifdef DEBUG_IRQUSE
+	printk("baboon_irq_enable(%d)\n", irq);
+#endif
+	baboon_active |= (1 << irq_idx);
+}
+
+void baboon_irq_disable(int irq) {
+	int irq_idx	= IRQ_IDX(irq);
+
+#ifdef DEBUG_IRQUSE
+	printk("baboon_irq_disable(%d)\n", irq);
+#endif
+	baboon_active &= ~(1 << irq_idx);
+}
+
+void baboon_irq_clear(int irq) {
+	int irq_idx	= IRQ_IDX(irq);
+
+	baboon->mb_ifr &= ~(1 << irq_idx);
+}
+
+int baboon_irq_pending(int irq)
+{
+	int irq_idx	= IRQ_IDX(irq);
+
+	return baboon->mb_ifr & (1 << irq_idx);
+}
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c
--- v2.3.44/linux/arch/m68k/mac/config.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/config.c	Sun Feb 13 11:21:42 2000
@@ -42,16 +42,6 @@
 #include <asm/mac_oss.h>
 #include <asm/mac_psc.h>
 
-/* Offset between Unix time (1970-based) and Mac time (1904-based) */
-
-#define MAC_TIME_OFFSET 2082844800
-
-/*
- * hardware reset vector
- */
-
-static void (*rom_reset)(void);
-
 /* Mac bootinfo struct */
 
 struct mac_booter_data mac_bi_data = {0,};
@@ -76,10 +66,11 @@
 extern void mackbd_leds(unsigned int leds);
 
 /* Mac specific timer functions */
+extern void mac_gettod (int *, int *, int *, int *, int *, int *);
 extern unsigned long mac_gettimeoffset (void);
-static void mac_gettod (int *, int *, int *, int *, int *, int *);
-static int mac_hwclk (int, struct hwclk_time *);
-static int mac_set_clock_mmss (unsigned long);
+extern int mac_hwclk (int, struct hwclk_time *);
+extern int mac_set_clock_mmss (unsigned long);
+extern int mac_get_irq_list(char *);
 extern void iop_preinit(void);
 extern void iop_init(void);
 extern void via_init(void);
@@ -87,6 +78,7 @@
 extern void via_flush_cache(void);
 extern void oss_init(void);
 extern void psc_init(void);
+extern void baboon_init(void);
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 extern void mac_mksound(unsigned int, unsigned int);
@@ -99,18 +91,6 @@
 extern void mac_debug_init(void);
 extern void mac_debugging_long(int, long);
 
-/* poweroff functions */
-extern void via_poweroff(void);
-extern void oss_poweroff(void);
-extern void adb_poweroff(void);
-extern void adb_hwreset(void);
-
-/* pram functions */
-extern __u32 via_read_time(void);
-extern void via_write_time(__u32);
-extern __u32 adb_read_time(void);
-extern void adb_write_time(__u32);
-
 #ifdef CONFIG_MAGIC_SYSRQ
 static char mac_sysrq_xlate[128] =
 	"\000sdfghzxcv\000bqwer"				/* 0x00 - 0x0f */
@@ -140,186 +120,6 @@
 
 extern int console_loglevel;
 
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static unsigned long mktime(unsigned int year, unsigned int mon,
-	unsigned int day, unsigned int hour,
-	unsigned int min, unsigned int sec)
-{
-	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
-		mon += 12;	/* Puts Feb last since it has leap day */
-		year -= 1;
-	}
-	return (((
-	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
-	      year*365 - 719499
-	    )*24 + hour /* now have hours */
-	   )*60 + min /* now have minutes */
-	  )*60 + sec; /* finally seconds */
-}
-
-/*
- * This function translates seconds since 1970 into a proper date.
- *
- * Algorithm cribbed from glibc2.1, __offtime().
- */
-#define SECS_PER_MINUTE (60)
-#define SECS_PER_HOUR  (SECS_PER_MINUTE * 60)
-#define SECS_PER_DAY   (SECS_PER_HOUR * 24)
-
-static void unmktime(unsigned long time, long offset,
-		     int *yearp, int *monp, int *dayp,
-		     int *hourp, int *minp, int *secp)
-{
-        /* How many days come before each month (0-12).  */
-	static const unsigned short int __mon_yday[2][13] =
-	{
-		/* Normal years.  */
-		{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
-		/* Leap years.  */
-		{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
-	};
-	long int days, rem, y, wday, yday;
-	const unsigned short int *ip;
-
-	days = time / SECS_PER_DAY;
-	rem = time % SECS_PER_DAY;
-	rem += offset;
-	while (rem < 0) {
-		rem += SECS_PER_DAY;
-		--days;
-	}
-	while (rem >= SECS_PER_DAY) {
-		rem -= SECS_PER_DAY;
-		++days;
-	}
-	*hourp = rem / SECS_PER_HOUR;
-	rem %= SECS_PER_HOUR;
-	*minp = rem / SECS_PER_MINUTE;
-	*secp = rem % SECS_PER_MINUTE;
-	/* January 1, 1970 was a Thursday. */
-	wday = (4 + days) % 7; /* Day in the week. Not currently used */
-	if (wday < 0) wday += 7;
-	y = 1970;
-
-#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
-#define __isleap(year)	\
-  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-
-	while (days < 0 || days >= (__isleap (y) ? 366 : 365))
-	{
-		/* Guess a corrected year, assuming 365 days per year.  */
-		long int yg = y + days / 365 - (days % 365 < 0);
-
-		/* Adjust DAYS and Y to match the guessed year.  */
-		days -= ((yg - y) * 365
-			 + LEAPS_THRU_END_OF (yg - 1)
-			 - LEAPS_THRU_END_OF (y - 1));
-		y = yg;
-	}
-	*yearp = y - 1900;
-	yday = days; /* day in the year.  Not currently used. */
-	ip = __mon_yday[__isleap(y)];
-	for (y = 11; days < (long int) ip[y]; --y)
-		continue;
-	days -= ip[y];
-	*monp = y;
-	*dayp = days + 1; /* day in the month */
-	return;
-}
-
-/*
- * Return the boot time for use in initializing the kernel clock.
- *
- * I'd like to read the hardware clock here but many machines read
- * the PRAM through ADB, and interrupts aren't initialized when this
- * is called so ADB obviously won't work.
- */
-
-static void mac_gettod(int *yearp, int *monp, int *dayp,
-		       int *hourp, int *minp, int *secp)
-{
-	/* Yes the GMT bias is backwards.  It looks like Penguin is
-           screwing up the boottime it gives us... This works for me
-           in Canada/Eastern but it might be wrong everywhere else. */
-	unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60,
-		yearp, monp, dayp, hourp, minp, secp);
-	/* For some reason this is off by one */
-	*monp = *monp + 1;
-}
-
-/* 
- * Read/write the hardware clock.
- */
-
-static int mac_hwclk(int op, struct hwclk_time *t)
-{
-	unsigned long now;
-
-	if (!op) { /* read */
-		if (macintosh_config->adb_type == MAC_ADB_II) {
-			now = via_read_time();
-		} else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
-			   (macintosh_config->adb_type == MAC_ADB_CUDA)) {
-			now = adb_read_time();
-		} else if (macintosh_config->adb_type == MAC_ADB_IOP) {
-			now = via_read_time();
-		} else {
-			now = MAC_TIME_OFFSET;
-		}
-
-		now -= MAC_TIME_OFFSET;
-
-		t->wday = 0;
-		unmktime(now, 0,
-			 &t->year, &t->mon, &t->day,
-			 &t->hour, &t->min, &t->sec);
-	} else { /* write */
-		now = mktime(t->year + 1900, t->mon + 1, t->day,
-			     t->hour, t->min, t->sec) + MAC_TIME_OFFSET;
-
-		if (macintosh_config->adb_type == MAC_ADB_II) {
-			via_write_time(now);
-		} else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
-			   (macintosh_config->adb_type == MAC_ADB_CUDA)) {
-			adb_write_time(now);
-		} else if (macintosh_config->adb_type == MAC_ADB_IOP) {
-			via_write_time(now);
-		}
-	}
-	return 0;
-}
-
-/*
- * Set minutes/seconds in the hardware clock
- */
-
-static int mac_set_clock_mmss (unsigned long nowtime)
-{
-	struct hwclk_time now;
-
-	mac_hwclk(0, &now);
-	now.sec = nowtime % 60;
-	now.min = (nowtime / 60) % 60;
-	mac_hwclk(1, &now);
-
-	return 0;
-}
-
 #if 0
 void mac_waitbut (void)
 {
@@ -330,9 +130,23 @@
 extern struct consw fb_con;
 extern struct fb_info *mac_fb_init(long *);
 
-    /*
-     *  Parse a Macintosh-specific record in the bootinfo
-     */
+extern void mac_default_handler(int, void *, struct pt_regs *);
+
+void (*mac_handlers[8])(int, void *, struct pt_regs *)=
+{
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler
+};
+
+/*
+ * Parse a Macintosh-specific record in the bootinfo
+ */
 
 int __init mac_parse_bootinfo(const struct bi_record *record)
 {
@@ -384,9 +198,9 @@
 }
 
 /*
- *	Flip into 24bit mode for an instant - flushes the L2 cache card. We
- *	have to disable interrupts for this. Our IRQ handlers will crap 
- *	themselves if they take an IRQ in 24bit mode!
+ * Flip into 24bit mode for an instant - flushes the L2 cache card. We
+ * have to disable interrupts for this. Our IRQ handlers will crap 
+ * themselves if they take an IRQ in 24bit mode!
  */
 
 static void mac_cache_card_flush(int writeback)
@@ -414,6 +228,8 @@
     enable_irq           = mac_enable_irq;
     disable_irq          = mac_disable_irq;
     mach_get_model	 = mac_get_model;
+    mach_default_handler = &mac_handlers;
+    mach_get_irq_list    = mac_get_irq_list;
     mach_gettimeoffset   = mac_gettimeoffset;
     mach_gettod          = mac_gettod;
     mach_hwclk           = mac_hwclk;
@@ -489,7 +305,6 @@
 static struct mac_model mac_data_table[]=
 {
 	/*
-	 *	The default machine, in case we get an unsupported one
 	 *	We'll pretend to be a Macintosh II, that's pretty safe.
 	 */
 
@@ -509,10 +324,6 @@
 	 *	Weirdified MacII hardware - all subtley different. Gee thanks
 	 *	Apple. All these boxes seem to have VIA2 in a different place to
 	 *	the MacII (+1A000 rather than +4000)
-	 *
-	 *	The IIfx apparently has different ADB hardware, and stuff
-	 *	so zany nobody knows how to drive it.
-	 *	Even so, with Marten's help we'll try to deal with it :-)
 	 * CSA: see http://developer.apple.com/technotes/hw/hw_09.html
 	 */
 
@@ -584,28 +395,33 @@
 	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_MACE,		MAC_NUBUS},
 
 	/*
-	 *      Power books - seem similar to early Quadras ? (most have 030 though)
-	 */
-
-	{	MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	/*	The PB150 has IDE, and IIci style VIA */
-	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_NONE, MAC_IDE_PB,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	/* These have onboard SONIC */
-	{	MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_SONIC, MAC_NUBUS},
-
-	/*
-	 *      Power book Duos - similar to Power books, I hope
+	 * The PowerBooks all the same "Combo" custom IC for SCSI and SCC
+	 * and a PMU (in two variations?) for ADB. Most of them use the
+	 * Quadra-style VIAs. A few models also have IDE from hell.
+	 */
+
+	{	MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_OLD,  MAC_IDE_PB,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB190,  "PowerBook 190",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_BABOON, MAC_SCC_QUADRA, MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	 MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS},
+
+	/*
+	 * PowerBook Duos are pretty much like normal PowerBooks
+	 * All of these probably have onboard SONIC in the Dock which
+	 * means we'll have to probe for it eventually.
+	 *
+	 * Are these reallly MAC_VIA_IIci? The developer notes for the
+	 * Duos show pretty much the same custom parts as in most of
+	 * the other PowerBooks which would imply MAC_VIA_QUADRA.
 	 */
 
-	/* All of these might have onboard SONIC in the Dock but I'm not quite sure */
 	{	MAC_MODEL_PB210,  "PowerBook Duo 210",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_PB250,  "PowerBook Duo 250",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -694,6 +510,7 @@
 	via_init();
 	oss_init();
 	psc_init();
+	baboon_init();
 }
 
 void mac_report_hardware(void)
@@ -706,137 +523,3 @@
 	strcpy(str,"Macintosh ");
 	strcat(str, macintosh_config->name);
 }
-
-/*
- *	The power switch - yes it's software!
- */
-
-void mac_poweroff(void)
-{
-	/*
-	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
-	 * work using the ADB packet method.  --David Kilzer
-	 */
-
-	if (oss_present) {
-		oss_poweroff();
-	} else if (macintosh_config->adb_type == MAC_ADB_II) {
-		via_poweroff();
-	} else {
-		adb_poweroff();
-	}
-}
-
-/* 
- * Not all Macs support software power down; for the rest, just 
- * try the ROM reset vector ...
- */
-void mac_reset(void)
-{
-	/*
-	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
-	 * work using the ADB packet method.  --David Kilzer
-	 */
-
-	if (macintosh_config->adb_type == MAC_ADB_II) {
-		unsigned long cpu_flags;
-
-		/* need ROMBASE in booter */
-		/* indeed, plus need to MAP THE ROM !! */
-
-		if (mac_bi_data.rombase == 0)
-			mac_bi_data.rombase = 0x40800000;
-
-		/* works on some */
-		rom_reset = (void *) (mac_bi_data.rombase + 0xa);
-
-		if (macintosh_config->ident == MAC_MODEL_SE30) {
-			/*
-			 * MSch: Machines known to crash on ROM reset ...
-			 */
-			printk("System halted.\n");
-			while(1);
-		} else {
-			save_flags(cpu_flags);
-			cli();
-
-			rom_reset();
-
-			restore_flags(cpu_flags);
-		}
-
-		/* We never make it this far... it usually panics above. */
-		printk ("Restart failed.  Please restart manually.\n");
-
-		/* XXX - delay do we need to spin here ? */
-		while(1);       /* Just in case .. */
-	} else if (macintosh_config->adb_type == MAC_ADB_IISI
-		|| macintosh_config->adb_type == MAC_ADB_CUDA) {
-		adb_hwreset();
-	} else if (CPU_IS_030) {
-
-		/* 030-specific reset routine.  The idea is general, but the
-		 * specific registers to reset are '030-specific.  Until I
-		 * have a non-030 machine, I can't test anything else.
-		 *  -- C. Scott Ananian <cananian@alumni.princeton.edu>
-		 */
-
-		unsigned long rombase = 0x40000000;
-
-		/* make a 1-to-1 mapping, using the transparent tran. reg. */
-		unsigned long virt = (unsigned long) mac_reset;
-		unsigned long phys = virt_to_phys(mac_reset);
-		unsigned long offset = phys-virt;
-		cli(); /* lets not screw this up, ok? */
-		__asm__ __volatile__(".chip 68030\n\t"
-				     "pmove %0,%/tt0\n\t"
-				     ".chip 68k"
-				     : : "m" ((phys&0xFF000000)|0x8777));
-		/* Now jump to physical address so we can disable MMU */
-		__asm__ __volatile__(
-                    ".chip 68030\n\t"
-		    "lea %/pc@(1f),%/a0\n\t"
-		    "addl %0,%/a0\n\t"/* fixup target address and stack ptr */
-		    "addl %0,%/sp\n\t" 
-		    "pflusha\n\t"
-		    "jmp %/a0@\n\t" /* jump into physical memory */
-		    "0:.long 0\n\t" /* a constant zero. */
-		    /* OK.  Now reset everything and jump to reset vector. */
-		    "1:\n\t"
-		    "lea %/pc@(0b),%/a0\n\t"
-		    "pmove %/a0@, %/tc\n\t" /* disable mmu */
-		    "pmove %/a0@, %/tt0\n\t" /* disable tt0 */
-		    "pmove %/a0@, %/tt1\n\t" /* disable tt1 */
-		    "movel #0, %/a0\n\t"
-		    "movec %/a0, %/vbr\n\t" /* clear vector base register */
-		    "movec %/a0, %/cacr\n\t" /* disable caches */
-		    "movel #0x0808,%/a0\n\t"
-		    "movec %/a0, %/cacr\n\t" /* flush i&d caches */
-		    "movew #0x2700,%/sr\n\t" /* set up status register */
-		    "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */
-		    "movec %/a0, %/isp\n\t" 
-		    "movel %1@(0x4),%/a0\n\t" /* load reset vector */
-		    "reset\n\t" /* reset external devices */
-		    "jmp %/a0@\n\t" /* jump to the reset vector */
-		    ".chip 68k"
-		    : : "r" (offset), "a" (rombase) : "a0");
-
-		/* should never get here */
-		sti(); /* sure, why not */
-		printk ("030 Restart failed.  Please restart manually.\n");
-		while(1);
-	} else {
-		/* We never make it here... The above shoule handle all cases. */
-		printk ("Restart failed.  Please restart manually.\n");
-
-		/* XXX - delay do we need to spin here ? */
-		while(1);       /* Just in case .. */
-	}
-}
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 8
- * End:
- */
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/iop.c linux/arch/m68k/mac/iop.c
--- v2.3.44/linux/arch/m68k/mac/iop.c	Tue Nov 23 22:42:20 1999
+++ linux/arch/m68k/mac/iop.c	Sun Feb 13 11:21:42 2000
@@ -319,7 +319,7 @@
 {
 	if (iop_ism_present) {
 		if (oss_present) {
-			request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+			sys_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
 					IRQ_FLG_LOCK, "ISM IOP",
 					(void *) IOP_NUM_ISM);
 			oss_irq_enable(IRQ_MAC_ADB);
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c
--- v2.3.44/linux/arch/m68k/mac/macints.c	Thu Nov 18 20:25:37 1999
+++ linux/arch/m68k/mac/macints.c	Sun Feb 13 11:21:42 2000
@@ -35,8 +35,8 @@
  *	3	- unused (?)
  *
  *	4	- SCC (slot number determined by reading RR3 on the SSC itself)
- *		  - slot 0: SCC channel A
- *		  - slot 1: SCC channel B
+ *		  - slot 1: SCC channel A
+ *		  - slot 2: SCC channel B
  *
  *	5	- unused (?)
  *		  [serial errors or special conditions seem to raise level 6
@@ -55,8 +55,8 @@
  *		  - slot 5: Slot $E
  *
  *	4	- SCC IOP
- *		  - slot 0: SCC channel A
- *		  - slot 1: SCC channel B
+ *		  - slot 1: SCC channel A
+ *		  - slot 2: SCC channel B
  *
  *	5	- ISM IOP (ADB?)
  *
@@ -100,19 +100,18 @@
  *   bits.  The handlers for this new machspec interrupt number are then
  *   called. This puts Nubus interrupts into the range 56-62.
  *
+ * - The Baboon interrupts (used on some PowerBooks) are an even more special
+ *   case. They're hidden behind the Nubus slot $C interrupt thus adding a
+ *   third layer of indirection. Why oh why did the Apple engineers do that?
+ *
  * - We support "fast" and "slow" handlers, just like the Amiga port. The
  *   fast handlers are called first and with all interrupts disabled. They
  *   are expected to execute quickly (hence the name). The slow handlers are
  *   called last with interrupts enabled and the interrupt level restored.
  *   They must therefore be reentrant.
  *
- * - Drivers should never try to request autovector interrupt numbers. It
- *   won't work.
- *
  *   TODO:
  *
- *   o Perhaps build some intelligence into mac_SCC_handler(); we could check
- *     the SCC ourselves and only call the handler for the appopriate channel.
  */
 
 #include <linux/types.h>
@@ -125,6 +124,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/traps.h>
+#include <asm/bootinfo.h>
 #include <asm/machw.h>
 #include <asm/macintosh.h>
 #include <asm/mac_via.h>
@@ -133,6 +133,18 @@
 #include <asm/macints.h>
 
 /*
+ * The mac_irq_list array is an array of linked lists of irq_node_t nodes.
+ * Each node contains one handler to be called whenever the interrupt
+ * occurs, with fast handlers listed before slow handlers.
+ */
+
+irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
+
+/* SCC interrupt mask */
+
+static int scc_mask;
+
+/*
  * VIA/RBV hooks
  */
 
@@ -176,6 +188,26 @@
 extern void iop_register_interrupts(void);
 
 /*
+ * Baboon hooks
+ */
+
+extern int baboon_present;
+
+extern void baboon_init(void);
+extern void baboon_register_interrupts(void);
+extern void baboon_irq_enable(int);
+extern void baboon_irq_disable(int);
+extern void baboon_irq_clear(int);
+extern int  baboon_irq_pending(int);
+
+/*
+ * SCC interrupt routines
+ */
+
+static void scc_irq_enable(int);
+static void scc_irq_disable(int);
+
+/*
  * console_loglevel determines NMI handler function
  */
 
@@ -184,17 +216,27 @@
 extern void mac_bang(int, void *, struct pt_regs *);
 
 void mac_nmi_handler(int, void *, struct pt_regs *);
-void mac_SCC_handler(int, void *, struct pt_regs *);
+void mac_debug_handler(int, void *, struct pt_regs *);
 
 /* #define DEBUG_MACINTS */
 
 void mac_init_IRQ(void)
 {
+        int i;
+
 #ifdef DEBUG_MACINTS
 	printk("mac_init_IRQ(): Setting things up...\n");
 #endif
+	/* Initialize the IRQ handler lists. Initially each list is empty, */
+
+	for (i = 0; i < NUM_MAC_SOURCES; i++) {
+		mac_irq_list[i] = NULL;
+	}
+
+	scc_mask = 0;
+
 	/* 
-	 * Register the handlers for the the master IRQ handlers
+	 * Now register the handlers for the the master IRQ handlers
 	 * at levels 1-7. Most of the work is done elsewhere.
 	 */
 
@@ -204,8 +246,9 @@
 		via_register_interrupts();
 	}
 	if (psc_present) psc_register_interrupts();
+	if (baboon_present) baboon_register_interrupts();
 	iop_register_interrupts();
-	request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler);
+	sys_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler);
 #ifdef DEBUG_MACINTS
 	printk("mac_init_IRQ(): Done!\n");
 #endif
@@ -284,27 +327,20 @@
 
 void mac_do_irq_list(int irq, struct pt_regs *fp)
 {
-	irq_node_t *node, *slow_nodes, **list = NULL;
+	irq_node_t *node, *slow_nodes;
 	unsigned long cpu_flags;
 
 	kstat.irqs[0][irq]++;
 
-	if (irq < VIA1_SOURCE_BASE) {
-		list = &autoirq_list[irq];
-	} else if (irq < NUM_MAC_SOURCES) {
-		list = &userirq_list[irq - VIA1_SOURCE_BASE];
-	}
-	if (!list) return;
-
 #ifdef DEBUG_SPURIOUS
-	if (!*list && (console_loglevel > 7)) {
+	if (!mac_irq_list[irq] && (console_loglevel > 7)) {
 		printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
 		return;
 	}
 #endif
 
 	/* serve first fast and normal handlers */
-	for (node = *list;
+	for (node = mac_irq_list[irq];
 	     node && (!(node->flags & IRQ_FLG_SLOW));
 	     node = node->next)
 		node->handler(irq, node->dev_id, fp);
@@ -329,7 +365,9 @@
 
 void mac_enable_irq (unsigned int irq)
 {
-	switch(IRQ_SRC(irq)) {
+	int irq_src	= IRQ_SRC(irq);
+
+	switch(irq_src) {
 		case 1: via_irq_enable(irq);
 			break;
 		case 2:
@@ -346,6 +384,12 @@
 				psc_irq_enable(irq);
 			} else if (oss_present) {
 				oss_irq_enable(irq);
+			} else if (irq_src == 4) {
+				scc_irq_enable(irq);
+			}
+			break;
+		case 8: if (baboon_present) {
+				baboon_irq_enable(irq);
 			}
 			break;
 	}
@@ -353,12 +397,13 @@
 
 void mac_disable_irq (unsigned int irq)
 {
-	switch(IRQ_SRC(irq)) {
+	int irq_src	= IRQ_SRC(irq);
+
+	switch(irq_src) {
 		case 1: via_irq_disable(irq);
 			break;
 		case 2:
-		case 7:
-			if (oss_present) {
+		case 7: if (oss_present) {
 				oss_irq_disable(irq);
 			} else {
 				via_irq_disable(irq);
@@ -371,6 +416,12 @@
 				psc_irq_disable(irq);
 			} else if (oss_present) {
 				oss_irq_disable(irq);
+			} else if (irq_src == 4) {
+				scc_irq_disable(irq);
+			}
+			break;
+		case 8: if (baboon_present) {
+				baboon_irq_disable(irq);
 			}
 			break;
 	}
@@ -397,6 +448,10 @@
 				oss_irq_clear(irq);
 			}
 			break;
+		case 8: if (baboon_present) {
+				baboon_irq_clear(irq);
+			}
+			break;
 	}
 }
 
@@ -434,29 +489,37 @@
 		    void (*handler)(int, void *, struct pt_regs *),
 		    unsigned long flags, const char *devname, void *dev_id)
 {
-	int vec, ret;
+	irq_node_t *node;
 
 #ifdef DEBUG_MACINTS
 	printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
 #endif
 
 	if (irq < VIA1_SOURCE_BASE) {
-		vec = VEC_SPUR + irq;
-	} else if (irq < NUM_MAC_SOURCES) {
-		vec = VEC_USER + irq - VIA1_SOURCE_BASE;
-	} else {
+		return sys_request_irq(irq, handler, flags, devname, dev_id);
+	}
+
+	if (irq >= NUM_MAC_SOURCES) {
 		printk ("%s: unknown irq %d requested by %s\n",
 		        __FUNCTION__, irq, devname);
-		return -EAGAIN;
 	}
 
-	ret = sys_request_listirq(vec, handler, flags, devname, dev_id);
-	if (!ret) {
-		vectors[vec] = autoirq_listhandler;
-		mac_enable_irq(irq);
-	}
+	/* Get a node and stick it onto the right list */
+
+	if (!(node = new_irq_node())) return -ENOMEM;
 
-	return ret;
+	node->handler	= handler;
+	node->flags	= flags;
+	node->dev_id	= dev_id;
+	node->devname	= devname;
+	node->next	= NULL;
+	mac_insert_irq(&mac_irq_list[irq], node);
+
+	/* Now enable the IRQ source */
+
+	mac_enable_irq(irq);
+
+	return 0;
 }
                             
 /*
@@ -465,30 +528,120 @@
 
 void mac_free_irq(unsigned int irq, void *dev_id)
 {
-	irq_node_t **list = NULL;
-	int vec = 0;
-
 #ifdef DEBUG_MACINTS
 	printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
 #endif
 
 	if (irq < VIA1_SOURCE_BASE) {
-		vec = VEC_SPUR + irq;
-		list = &autoirq_list[irq];
-	} else if (irq < NUM_MAC_SOURCES) {
-		vec = VEC_USER + irq - VIA1_SOURCE_BASE;
-		list = &userirq_list[irq - VIA1_SOURCE_BASE];
+		return sys_free_irq(irq, dev_id);
+	}
+
+	if (irq >= NUM_MAC_SOURCES) {
+		printk ("%s: unknown irq %d freed\n",
+		        __FUNCTION__, irq);
+		return;
 	}
-	if (!list) return;
 
-	sys_free_irq(vec, dev_id);
+	mac_delete_irq(&mac_irq_list[irq], dev_id);
 
 	/* If the list for this interrupt is */
 	/* empty then disable the source.    */
 
-	if (!*list) {
+	if (!mac_irq_list[irq]) {
 		mac_disable_irq(irq);
-		vectors[vec] = bad_interrupt;
+	}
+}
+
+/*
+ * Generate a pretty listing for /proc/interrupts
+ *
+ * By the time we're called the autovector interrupt list has already been
+ * generated, so we just need to do the machspec interrupts.
+ *
+ * 990506 (jmt) - rewritten to handle chained machspec interrupt handlers.
+ *                Also removed display of num_spurious it is already
+ *		  displayed for us as autovector irq 0.
+ */
+
+int mac_get_irq_list (char *buf)
+{
+	int i, len = 0;
+	irq_node_t *node;
+	char *base;
+
+	/* Don't do Nubus interrupts in this loop; we do them separately  */
+	/* below so that we can print slot numbers instead of IRQ numbers */
+
+	for (i = VIA1_SOURCE_BASE ; i < NUM_MAC_SOURCES ; ++i) {
+
+		/* Nonexistant interrupt or nothing registered; skip it. */
+
+		if ((node = mac_irq_list[i]) == NULL) continue;
+		if (node->flags & IRQ_FLG_STD) continue;
+
+		base = "";
+		switch(IRQ_SRC(i)) {
+			case 1: base = "via1";
+				break;
+			case 2: if (oss_present) {
+					base = "oss";
+				} else {
+					base = "via2";
+				}
+				break;
+			case 3:
+			case 4:
+			case 5:
+			case 6: if (psc_present) {
+					base = "psc";
+				} else if (oss_present) {
+					base = "oss";
+				} else {
+					if (IRQ_SRC(i) == 4) base = "scc";
+				}
+				break;
+			case 7: base = "nbus";
+				break;
+			case 8: base = "bbn";
+				break;
+		}
+		len += sprintf(buf+len, "%4s %2d: %10u ",
+				base, i, kstat.irqs[0][i]);
+
+		do {
+			if (node->flags & IRQ_FLG_FAST) {
+				len += sprintf(buf+len, "F ");
+			} else if (node->flags & IRQ_FLG_SLOW) {
+				len += sprintf(buf+len, "S ");
+			} else {
+				len += sprintf(buf+len, "  ");
+			}
+			len += sprintf(buf+len, "%s\n", node->devname);
+			if ((node = node->next)) {
+				len += sprintf(buf+len, "                    ");
+			}
+		} while(node);
+
+	}
+	return len;
+}
+
+void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+#ifdef DEBUG_SPURIOUS
+	if (console_loglevel > 6) {
+		printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
+	}
+#endif
+}
+
+static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (num_debug[irq] < 10) {
+		printk("DEBUG: Unexpected IRQ %d\n", irq);
+		num_debug[irq]++;
 	}
 }
 
@@ -543,12 +696,53 @@
 }
 
 /*
- *	SCC master interrupt handler; sole purpose: pass the registered 
- *	async struct to the SCC handler proper.
+ * Simple routines for masking and unmasking
+ * SCC interrupts in cases where this can't be
+ * done in hardware (only the PSC can do that.)
+ */
+
+static void scc_irq_enable(int irq) {
+	int irq_idx     = IRQ_IDX(irq);
+
+	scc_mask |= (1 << irq_idx);
+}
+
+static void scc_irq_disable(int irq) {
+	int irq_idx     = IRQ_IDX(irq);
+
+	scc_mask &= ~(1 << irq_idx);
+}
+
+/*
+ * SCC master interrupt handler. We have to do a bit of magic here
+ * to figure out what channel gave us the interrupt; putting this
+ * here is cleaner than hacking it into drivers/char/macserial.c.
  */
 
-void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
+void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
 {
-	mac_do_irq_list(IRQ_SCCA, regs);
-	mac_do_irq_list(IRQ_SCCB, regs);
+	volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2;
+	unsigned char reg;
+	unsigned long cpu_flags;
+
+	/* Read RR3 from the chip. Always do this on channel A */
+	/* This must be an atomic operation so disable irqs.   */
+
+	save_flags(cpu_flags); cli();
+	*scc = 3;
+	reg = *scc;
+	restore_flags(cpu_flags);
+
+	/* Now dispatch. Bits 0-2 are for channel B and */
+	/* bits 3-5 are for channel A. We can safely    */
+	/* ignore the remaining bits here.              */
+	/*                                              */
+	/* Note that we're ignoring scc_mask for now.   */
+	/* If we actually mask the ints then we tend to */
+	/* get hammered by very persistant SCC irqs,    */
+	/* and since they're autovector interrupts they */
+	/* pretty much kill the system.                 */
+
+	if (reg & 0x38) mac_do_irq_list(IRQ_SCCA, regs);
+	if (reg & 0x07) mac_do_irq_list(IRQ_SCCB, regs);
 }
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c
--- v2.3.44/linux/arch/m68k/mac/mackeyb.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/mac/mackeyb.c	Wed Dec 31 16:00:00 1969
@@ -1,762 +0,0 @@
-/*
- * linux/arch/m68k/mac/mackeyb.c
- *
- * Keyboard driver for Macintosh computers.
- *
- * Adapted from drivers/macintosh/key_mac.c and arch/m68k/atari/akakeyb.c 
- * (see that file for its authors and contributors).
- *
- * Copyright (C) 1997 Michael Schmitz.
- *
- * 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.
- */
-
-/*
- * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c)
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-/* keyb */
-#include <linux/keyboard.h>
-#include <linux/random.h>
-#include <linux/delay.h>
-/* keyb */
-
-#include <asm/setup.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-/* for keyboard_input stuff */
-#include <asm/adb.h>
-#define KEYB_KEYREG	0	/* register # for key up/down data */
-#define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
-#define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
-/* end keyboard_input stuff */
-
-#include <linux/kbd_kern.h>
-#include <linux/kbd_ll.h>
-
-static void kbd_repeat(unsigned long);
-static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
-static int last_keycode;
-
-static void input_keycode(int, int);
-
-extern struct kbd_struct kbd_table[];
-
-extern void adb_bus_init(void);
-extern void handle_scancode(unsigned char, int);
-extern void put_queue(int);
-
-/* keyb */
-static void mac_leds_done(struct adb_request *);
-static void keyboard_input(unsigned char *, int, struct pt_regs *);
-static void mouse_input(unsigned char *, int, struct pt_regs *);
-
-#ifdef CONFIG_ADBMOUSE
-/* XXX: Hook for mouse driver */
-void (*adb_mouse_interrupt_hook)(unsigned char *, int);
-int adb_emulate_buttons = 0;
-int adb_button2_keycode = 0x7d;	/* right control key */
-int adb_button3_keycode = 0x7c; /* right option key */
-#endif
-
-/* The mouse driver - for debugging */
-extern void adb_mouse_interrupt(char *, int);
-/* end keyb */
-
-/* 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, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* 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,
-};
-
-/*
- * Mac private key maps
- */
-u_short mac_plain_map[NR_KEYS] __initdata = {
-	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
-	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
-	0xfb79,	0xfb74,	0xf031,	0xf032,	0xf033,	0xf034,	0xf036,	0xf035,
-	0xf03d,	0xf039,	0xf037,	0xf02d,	0xf038,	0xf030,	0xf05d,	0xfb6f,
-	0xfb75,	0xf05b,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf027,
-	0xfb6b,	0xf03b,	0xf05c,	0xf02c,	0xf02f,	0xfb6e,	0xfb6d,	0xf02e,
-	0xf009,	0xf020,	0xf060,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xfb61,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf109,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
-	0xf101,	0xf119,	0xf100,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short mac_shift_map[NR_KEYS] __initdata = {
-	0xfb41,	0xfb53,	0xfb44,	0xfb46,	0xfb48,	0xfb47,	0xfb5a,	0xfb58,
-	0xfb43,	0xfb56,	0xf200,	0xfb42,	0xfb51,	0xfb57,	0xfb45,	0xfb52,
-	0xfb59,	0xfb54,	0xf021,	0xf040,	0xf023,	0xf024,	0xf05e,	0xf025,
-	0xf02b,	0xf028,	0xf026,	0xf05f,	0xf02a,	0xf029,	0xf07d,	0xfb4f,
-	0xfb55,	0xf07b,	0xfb49,	0xfb50,	0xf201,	0xfb4c,	0xfb4a,	0xf022,
-	0xfb4b,	0xf03a,	0xf07c,	0xf03c,	0xf03f,	0xfb4e,	0xfb4d,	0xf03e,
-	0xf009,	0xf020,	0xf07e,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xfb41,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf10e,	0xf10f,	0xf110,	0xf10c,	0xf111,	0xf112,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf203,	0xf200,	0xf113,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf20b,	0xf116,	0xf10d,	0xf117,
-	0xf10b,	0xf20a,	0xf10a,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short mac_altgr_map[NR_KEYS] __initdata = {
-	0xf914,	0xfb73,	0xf917,	0xf919,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
-	0xf916,	0xfb76,	0xf200,	0xf915,	0xfb71,	0xfb77,	0xf918,	0xfb72,
-	0xfb79,	0xfb74,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
-	0xf200,	0xf05d,	0xf07b,	0xf05c,	0xf05b,	0xf07d,	0xf07e,	0xfb6f,
-	0xfb75,	0xf200,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf200,
-	0xfb6b,	0xf200,	0xf200,	0xf200,	0xf200,	0xfb6e,	0xfb6d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf90a,	0xf90b,	0xf90c,	0xf90d,	0xf90e,	0xf90f,
-	0xf910,	0xf911,	0xf914,	0xf912,	0xf913,	0xf200,	0xf200,	0xf200,
-	0xf510,	0xf511,	0xf512,	0xf50e,	0xf513,	0xf514,	0xf200,	0xf516,
-	0xf200,	0xf10c,	0xf200,	0xf202,	0xf200,	0xf515,	0xf200,	0xf517,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf50f,	0xf117,
-	0xf50d,	0xf119,	0xf50c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short mac_ctrl_map[NR_KEYS] __initdata = {
-	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
-	0xf019,	0xf014,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01e,	0xf01d,
-	0xf200,	0xf200,	0xf01f,	0xf01f,	0xf07f,	0xf200,	0xf01d,	0xf00f,
-	0xf015,	0xf01b,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf007,
-	0xf00b,	0xf200,	0xf01c,	0xf200,	0xf07f,	0xf00e,	0xf00d,	0xf20e,
-	0xf200,	0xf000,	0xf000,	0xf008,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf001,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf204,	0xf200,	0xf109,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
-	0xf101,	0xf119,	0xf100,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short mac_shift_ctrl_map[NR_KEYS] __initdata = {
-	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
-	0xf019,	0xf014,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf00f,
-	0xf015,	0xf200,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf200,
-	0xf00b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf00e,	0xf00d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf001,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf200,	0xf117,
-	0xf200,	0xf119,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf20c,
-};
-
-u_short mac_alt_map[NR_KEYS] __initdata = {
-	0xf861,	0xf873,	0xf864,	0xf866,	0xf868,	0xf867,	0xf87a,	0xf878,
-	0xf863,	0xf876,	0xf200,	0xf862,	0xf871,	0xf877,	0xf865,	0xf872,
-	0xf879,	0xf874,	0xf831,	0xf832,	0xf833,	0xf834,	0xf836,	0xf835,
-	0xf83d,	0xf839,	0xf837,	0xf82d,	0xf838,	0xf830,	0xf85d,	0xf86f,
-	0xf875,	0xf85b,	0xf869,	0xf870,	0xf80d,	0xf86c,	0xf86a,	0xf827,
-	0xf86b,	0xf83b,	0xf85c,	0xf82c,	0xf82f,	0xf86e,	0xf86d,	0xf82e,
-	0xf809,	0xf820,	0xf860,	0xf87f,	0xf200,	0xf81b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf210,	0xf211,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf900,	0xf901,	0xf902,	0xf903,	0xf904,	0xf905,
-	0xf906,	0xf907,	0xf861,	0xf908,	0xf909,	0xf200,	0xf200,	0xf200,
-	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
-	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf509,	0xf200,	0xf50b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
-	0xf501,	0xf119,	0xf500,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short mac_ctrl_alt_map[NR_KEYS] __initdata = {
-	0xf801,	0xf813,	0xf804,	0xf806,	0xf808,	0xf807,	0xf81a,	0xf818,
-	0xf803,	0xf816,	0xf200,	0xf802,	0xf811,	0xf817,	0xf805,	0xf812,
-	0xf819,	0xf814,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80f,
-	0xf815,	0xf200,	0xf809,	0xf810,	0xf201,	0xf80c,	0xf80a,	0xf200,
-	0xf80b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80e,	0xf80d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf801,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
-	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf509,	0xf200,	0xf50b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
-	0xf501,	0xf119,	0xf500,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-extern unsigned int keymap_count;
-
-/*
- * Misc. defines for testing 
- */
-
-extern int console_loglevel;
-
-static struct adb_request led_request;
-extern int in_keybinit;
-
-/*
- * machdep keyboard routines, interface and key repeat method modeled after
- * drivers/macintosh/keyb_mac.c
- */
-
-int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode)
-{
-	if (!raw_mode) {
-		/*
-		 * Convert R-shift/control/option to L version.
-		 * Remap keycode 0 (A) to the unused keycode 0x5a.
-		 * Other parts of the system assume 0 is not a valid keycode.
-		 */
-		switch (keycode) {
-		case 0x7b: keycode = 0x38; break; /* R-shift */
-		case 0x7c: keycode = 0x3a; break; /* R-option */
-		case 0x7d: keycode = 0x36; break; /* R-control */
-		case 0:	   keycode = 0x5a; break; /* A */
-		}
-	}
-	*keycodep = keycode;
-	return 1;
-}
-
-int mac_kbd_unexpected_up(unsigned char keycode)
-{
-	return 0x80;
-}
-
-static void
-keyboard_input(unsigned char *data, int nb, struct pt_regs *regs)
-{
-	/* first check this is from register 0 */
-	if (nb != 5 || (data[2] & 3) != KEYB_KEYREG)
-		return;		/* ignore it */
-	kbd_pt_regs = regs;
-	input_keycode(data[3], 0);
-	if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f)))
-		input_keycode(data[4], 0);
-}
-
-static void
-input_keycode(int keycode, int repeat)
-{
-	struct kbd_struct *kbd;
-	int up_flag;
-
- 	kbd = kbd_table + fg_console;
-	up_flag = (keycode & 0x80);
-        keycode &= 0x7f;
-
-	if (!repeat)
-		del_timer(&repeat_timer);
-
-#ifdef CONFIG_ADBMOUSE
-	/*
-	 * XXX: Add mouse button 2+3 fake codes here if mouse open.
-	 *	As we only report up/down events, keep track of faked buttons.
-	 *	Really messy; might need to check if keyboard is in
-	 *	VC_RAW mode for X?.
-	 *	Might also want to know how many buttons need to be emulated.
-	 *	-> hide this as function in arch/m68k/mac ?
-	 *	Current emulation buttons: right alt/option and control
-	 *	(wanted: command and alt/option, or KP= and KP( ...)
-	 *	Debug version; might be rewritten to be faster on normal keys.
-	 */
-	if (adb_emulate_buttons 
-	    && (adb_mouse_interrupt_hook || console_loglevel >= 8)) {
-		unsigned char button, button2, button3, fake_event;
-		static unsigned char button2state=0, button3state=0; /* up */
-		/* faked ADB packet */
-		static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 };
-
-		button = 0;
-		fake_event = 0;
-		if (keycode == adb_button2_keycode) {	/* which 'button' ? */
-			/* R-option */
-			button2 = (!up_flag);		/* new state */
-			if (button2 != button2state)	/* change ? */
-				button = 2; 
-			button2state = button2;		/* save state */
-			fake_event = 2;
-		} else if (keycode == adb_button3_keycode) {
-			/* R-control */
-			button3 = (!up_flag);		/* new state */
-			if (button3 != button3state)	/* change ? */ 
-				button = 3; 
-			button3state = button3; 	/* save state */
-			fake_event = 3;
-		}
-#ifdef DEBUG_ADBMOUSE
-		if (fake_event && console_loglevel >= 8)
-			printk("fake event: button2 %d button3 %d button %d\n",
-				 button2state, button3state, button);
-#endif
-		if (button) {		/* there's been a button state change */
-			/* fake a mouse packet : send all bytes, change one! */
-			data[button] = (up_flag ? 0x80 : 0);
-			if (adb_mouse_interrupt_hook)
-				adb_mouse_interrupt_hook(data, 4);
-#ifdef DEBUG_ADBMOUSE
-			else
-				printk("mouse_fake: data %2x %2x %2x buttons %2x \n", 
-					data[1], data[2], data[3],
-					~( (data[1] & 0x80 ? 0 : 4) 
-					 | (data[2] & 0x80 ? 0 : 1) 
-					 | (data[3] & 0x80 ? 0 : 2) )&7 );
-#endif
-		}
-		/*
-		 * for mouse 3-button emulation: don't process 'fake' keys!
-		 * Keys might autorepeat, and console state gets generally messed
-		 * up enough so that selection stops working.
-		 */
-		if (fake_event)
-			return;
-	}
-#endif /* CONFIG_ADBMOUSE */
-
-	/*
-	 * Convert R-shift/control/option to L version.
-	 */
-	switch (keycode) {
-		case 0x7b: keycode = 0x38; break; /* R-shift */
-		case 0x7c: keycode = 0x3a; break; /* R-option */
-		case 0x7d: keycode = 0x36; break; /* R-control */
-		case 0x0:  if (kbd->kbdmode != VC_RAW) 
-			       keycode = 0x5a; /* A; keycode 0 deprecated */
-			       break; 
-	}
-
-	if (kbd->kbdmode != VC_RAW) {
-		if (!up_flag && !dont_repeat[keycode]) {
-			last_keycode = keycode;
-			repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
-			add_timer(&repeat_timer);
-		}
-
-		/*
-		 * XXX fix caps-lock behaviour by turning the key-up
-		 * transition into a key-down transition.
-		 * MSch: need to turn each caps-lock event into a down-up
-		 * double event (keyboard code assumes caps-lock is a toggle)
-		 * 981127: fix LED behavior (kudos atong!)
-		 */
-		switch (keycode) {
-		case 0x39:
-			handle_scancode(keycode, 1);	/* down */
-			up_flag = 0x80;			/* see below ... */
-		 	mark_bh(KEYBOARD_BH);
-			break;
-		 case 0x47:
-		 	mark_bh(KEYBOARD_BH);
-		 	break;
-		}
-	}
-
-	handle_scancode(keycode, !up_flag);
-}
-
-static void
-kbd_repeat(unsigned long xxx)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	input_keycode(last_keycode, 1);
-	restore_flags(flags);
-}
-
-  /* [ACA:23-Mar-97] Three button mouse support.  This is designed to
-     function with MkLinux DR-2.1 style X servers.  It only works with
-     three-button mice that conform to Apple's multi-button mouse
-     protocol. */
-
-  /*
-    The X server for MkLinux DR2.1 uses the following unused keycodes to
-    read the mouse:
-
-    0x7e  This indicates that the next two keycodes should be interpreted
-          as mouse information.  The first following byte's high bit
-          represents the state of the left button.  The lower seven bits
-          represent the x-axis acceleration.  The lower seven bits of the
-          second byte represent y-axis acceleration.
-
-    0x3f  The x server interprets this keycode as a middle button
-          release.
-
-    0xbf  The x server interprets this keycode as a middle button
-          depress.
-
-    0x40  The x server interprets this keycode as a right button
-          release.
-
-    0xc0  The x server interprets this keycode as a right button
-          depress.
-
-    NOTES: There should be a better way of handling mice in the X server.
-    The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead
-    of two.  The three mouse buttons should then, in the X server, be read
-    as the high-bits of all three bytes.  The x and y motions can still be
-    in the first two bytes.  Maybe I'll do this...
-  */
-
-  /*
-    Handler 4 -- Apple Extended mouse protocol.
-
-    For Apple's 3-button mouse protocol the data array will contain the
-    following values:
-
-		BITS    COMMENTS
-    data[0] = 0000 0000 ADB packet identifer.
-    data[1] = 0100 0000 Extended protocol register.
-	      Bits 6-7 are the device id, which should be 1.
-	      Bits 4-5 are resolution which is in "units/inch".
-	      The Logitech MouseMan returns these bits clear but it has
-	      200/300cpi resolution.
-	      Bits 0-3 are unique vendor id.
-    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
-	      Bits 2-3 should be 8 + 4.
-		      Bits 4-7 should be 3 for a mouse device.
-    data[3] = bxxx xxxx Left button and x-axis motion.
-    data[4] = byyy yyyy Second button and y-axis motion.
-    data[5] = byyy bxxx Third button and fourth button.  Y is additional
-	      high bits of y-axis motion.  XY is additional
-	      high bits of x-axis motion.
-
-    NOTE: data[0] and data[2] are confirmed by the parent function and
-    need not be checked here.
-  */
-
-  /*
-    Handler 1 -- 100cpi original Apple mouse protocol.
-    Handler 2 -- 200cpi original Apple mouse protocol.
-
-    For Apple's standard one-button mouse protocol the data array will
-    contain the following values:
-
-                BITS    COMMENTS
-    data[0] = 0000 0000 ADB packet identifer.
-    data[1] = ???? ???? (?)
-    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
-    data[3] = bxxx xxxx First button and x-axis motion.
-    data[4] = byyy yyyy Second button and y-axis motion.
-
-    NOTE: data[0] is confirmed by the parent function and need not be
-    checked here.
-  */
-
-static void
-mouse_input(unsigned char *data, int nb, struct pt_regs *regs)
-{
-	struct kbd_struct *kbd;
-	int i;
-
-	if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) {
-		printk("data from mouse:");
-		for (i = 0; i < nb; ++i)
-			printk(" %x", data[i]);
-		printk("\n");
-		return;
-	}
-
-	if (adb_mouse_interrupt_hook) {
-		adb_mouse_interrupt_hook(data+2, nb-2);
-		/*
-		 * passing the mouse data to i.e. the X server as done for
-		 * Xpmac will confuse applications on a sane X server :-)
-		 */
-		return;
-	} 
-#ifdef DEBUG_ADBMOUSE
-	else
-		if (console_loglevel >= 8)
-		    printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", 
-			data[3], data[4], data[5],
-			~((data[3] & 0x80 ? 0 : 4) 
-			| (data[4] & 0x80 ? 0 : 1)
-			| (data[5] & 0x80 ? 0 : 2))&7,
-			((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ),
-			((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) );
-#endif
-
-
-	kbd = kbd_table + fg_console;
-
-#if 0	/* The entirely insane way of MkLinux handling mouse input */
-	/* Requires put_queue which is static in keyboard.c :-( */
-	/* Only send mouse codes when keyboard is in raw mode. */
-	if (kbd->kbdmode == VC_RAW) {
-		static unsigned char uch_ButtonStateSecond = 0;
-		unsigned char uchButtonSecond;
-
-		/* Send first button, second button and movement. */
-		put_queue( 0x7e );
-		put_queue( data[3] );
-		put_queue( data[4] );
-
-		/* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
-
-		/* Store the button state. */
-		uchButtonSecond = (data[4] & 0x80);
-
-		/* Send second button. */
-		if (uchButtonSecond != uch_ButtonStateSecond) {
-			put_queue( 0x3f | uchButtonSecond );
-			uch_ButtonStateSecond = uchButtonSecond;
-		}
-
-		/* Macintosh 3-button mouse (handler 4). */
-		if ((nb == 6) && (data[1] & 0x40)) {
-			static unsigned char uch_ButtonStateThird = 0;
-			unsigned char uchButtonThird;
-
-			/* Store the button state for speed. */
-			uchButtonThird = (data[5] & 0x80);
-
-			/* Send third button. */
-			if (uchButtonThird != uch_ButtonStateThird) {
-				put_queue( 0x40 | uchButtonThird );
-				uch_ButtonStateThird = uchButtonThird;
-			}
-		}
-	}
-#endif	/* insane MkLinux mouse hack */
-}
-
-/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
-static unsigned char mac_ledmap[8] = {
-    0,		/* none */
-    4,		/* scroll lock */
-    1,		/* num lock */
-    5,		/* scroll + num lock */
-    2,		/* caps lock */
-    6,		/* caps + scroll lock */
-    3,		/* caps + num lock */
-    7,		/* caps + num + scroll lock */
-};
-
-static int leds_pending;
-
-void mac_kbd_leds(unsigned int leds)
-{
-	if (led_request.got_reply) {
-#ifdef DEBUG_ADB
-		if (console_loglevel == 10)
-			printk("mac_kbd_leds: got reply, sending request!\n");
-#endif
-		adb_request(&led_request, mac_leds_done, 4, ADB_PACKET,
-			     ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
-			     0xff, ~mac_ledmap[leds]);
-	} else
-		leds_pending = leds | 0x100;
-}
-
-static void mac_leds_done(struct adb_request *req)
-{
-	int leds;
-
-	if (leds_pending) {
-		leds = leds_pending & 0xff;
-		leds_pending = 0;
-		mac_kbd_leds(leds);
-	}
-	mark_bh(KEYBOARD_BH);
-}
-
-int mac_kbdrate(struct kbd_repeat *k)
-{
-	return 0;
-}
-
-int __init mac_keyb_init(void)
-{
-	static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req;
-	volatile int ct;
-
-	/* setup key map */
-	memcpy(key_maps[0], mac_plain_map, sizeof(plain_map));
-	memcpy(key_maps[1], mac_shift_map, sizeof(plain_map));
-	memcpy(key_maps[2], mac_altgr_map, sizeof(plain_map));
-	memcpy(key_maps[4], mac_ctrl_map, sizeof(plain_map));
-	memcpy(key_maps[5], mac_shift_ctrl_map, sizeof(plain_map));
-	memcpy(key_maps[8], mac_alt_map, sizeof(plain_map));
-	memcpy(key_maps[12], mac_ctrl_alt_map, sizeof(plain_map));
-
-	/* initialize mouse interrupt hook */
-	adb_mouse_interrupt_hook = NULL;
-
-	/*
-	 * Might put that someplace else, possibly ....
-	 */
-	adb_bus_init();
-
-	/* the input functions ... */	
-	adb_register(ADB_KEYBOARD, keyboard_input);
-	adb_register(ADB_MOUSE, mouse_input);
-
-	/* turn on ADB auto-polling in the CUDA */
-	
-	/*
-	 *	Older boxes don't support CUDA_* targets and CUDA commands
-	 *	instead we emulate them in the adb_request hook to make
-	 *	the code interfaces saner.
-	 *
-	 *	Note XXX: the Linux PMac and this code both assume the
-	 *	devices are at their primary ids and do not do device
-	 *	assignment. This isn't ideal. We should fix it to follow
-	 *	the reassignment specs.
-	 */
-
-	if (macintosh_config->adb_type == MAC_ADB_CUDA) {
-		printk("CUDA autopoll on ...\n");
-		adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
-		ct=0; 
-		while (!autopoll_req.got_reply && ++ct<1000)
-		{
-				udelay(10);
-		}
-		if(ct==1000) {
-			printk("Keyboard timed out.\n");
-			autopoll_req.got_reply = 1;
-		}
-	}
-
-	/*
-	 *	XXX: all ADB requests now in CUDA format; adb_request takes 
-	 *	care of that for other Macs.
-	 */
-
-	printk("Configuring keyboard:\n");
-
-	udelay(3000);
-
-	/* 
-	 * turn on all leds - the keyboard driver will turn them back off 
-	 * via mac_kbd_leds if everything works ok!
-	 */
-	printk("leds on ...\n");
-	adb_request(&led_request, NULL, 4, ADB_PACKET,
-		     ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7);
-
-	/*
-	 * The polling stuff should go away as soon as the ADB driver is stable
-	 */
-	ct = 0;
-	while (!led_request.got_reply && ++ct<1000)
-	{
-		udelay(10);
-	}
-	if(ct==1000) {
-		printk("keyboard timed out.\n");
-		led_request.got_reply  = 1;
-	}
-
-#if 1
-	printk("configuring coding mode ...\n");
-
-	udelay(3000);
-
-	/* 
-	 * get the keyboard to send separate codes for
-	 * left and right shift, control, option keys. 
-	 */
-	adb_request(&confcod_req, NULL, 4, ADB_PACKET, 
-		     ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
-
-	ct=0; 
-	while (!confcod_req.got_reply && ++ct<1000)
-	{
-		udelay(10);
-	}
-	if(ct==1000) {
-		printk("keyboard timed out.\n");
-		confcod_req.got_reply  = 1;
-	}
-#endif
-
-#if 0	/* seems to hurt, at least Geert's Mac */
-	printk("Configuring mouse (3-button mode) ...\n");
-
-	udelay(3000);
-
-	/* 
-	 * XXX: taken from the PPC driver again ... 
-	 * Try to switch the mouse (id 3) to handler 4, for three-button
-	 * mode. (0x20 is Service Request Enable, 0x03 is Device ID). 
-	 */
-	adb_request(&mouse_req, NULL, 4, ADB_PACKET,
-		    ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
-
-	ct=0; 
-	while (!mouse_req.got_reply && ++ct<1000)
-	{
-		udelay(10);
-	}
-	if(ct==1000)
-		printk("Mouse timed out.\n");
-#endif
-
-#if 0
-	printk("Start polling keyboard ...\n");
-
-	/* 
-	 *	get the keyboard to send data back, via the adb_input hook
-	 *	XXX: was never used properly, and the driver takes care
-	 *	of polling and timeout retransmits now.
-	 *	Might be of use if we want to start talking to a specific
-	 *	device here...
-	 */
-	adb_request(&readkey_req, NULL, 2, ADB_PACKET, 
-		     ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG));
-#endif
-
-	in_keybinit = 0;
-	printk("keyboard init done\n");
-
-	return 0;
-}
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/misc.c linux/arch/m68k/mac/misc.c
--- v2.3.44/linux/arch/m68k/mac/misc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/misc.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,689 @@
+/*
+ * Miscellaneous Mac68K-specific stuff 
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/setup.h>
+#include <asm/macintosh.h>
+#include <asm/mac_via.h>
+#include <asm/mac_oss.h>
+
+#define BOOTINFO_COMPAT_1_0
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/machdep.h>
+
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+
+#define RTC_OFFSET 2082844800
+
+extern struct mac_booter_data mac_bi_data;
+static void (*rom_reset)(void);
+
+/*
+ * Return the current time as the number of seconds since January 1, 1904.
+ */
+
+static long adb_read_time(void)
+{
+	volatile struct adb_request req;
+	long time;
+
+	adb_request((struct adb_request *) &req, NULL,
+			ADBREQ_RAW|ADBREQ_SYNC,
+			2, CUDA_PACKET, CUDA_GET_TIME);
+
+	time = (req.reply[3] << 24) | (req.reply[4] << 16)
+		| (req.reply[5] << 8) | req.reply[6];
+	return time - RTC_OFFSET;
+}
+
+/*
+ * Set the current system time
+ */
+
+static void adb_write_time(long data)
+{
+	volatile struct adb_request req;
+
+	data += RTC_OFFSET;
+	
+	adb_request((struct adb_request *) &req, NULL,
+			ADBREQ_RAW|ADBREQ_SYNC,
+			6, CUDA_PACKET, CUDA_SET_TIME,
+			(data >> 24) & 0xFF, (data >> 16) & 0xFF,
+			(data >> 8) & 0xFF, data & 0xFF);
+}
+
+/*
+ * Get a byte from the NVRAM
+ */
+
+static __u8 adb_read_pram(int offset)
+{
+	volatile struct adb_request req;
+
+	adb_request((struct adb_request *) &req, NULL,
+			ADBREQ_RAW|ADBREQ_SYNC,
+			4, CUDA_PACKET, CUDA_GET_PRAM,
+			(offset >> 8) & 0xFF, offset & 0xFF);
+	return req.reply[3];
+}
+
+/*
+ * Write a byte to the NVRAM
+ */
+
+static void adb_write_pram(int offset, __u8 data)
+{
+	volatile struct adb_request req;
+
+	adb_request((struct adb_request *) &req, NULL,
+			ADBREQ_RAW|ADBREQ_SYNC,
+			5, CUDA_PACKET, CUDA_SET_PRAM,
+			(offset >> 8) & 0xFF, offset & 0xFF,
+			data);
+}
+
+/*
+ * VIA PRAM/RTC access routines
+ *
+ * Must be called with interrupts disabled and
+ * the RTC should be enabled.
+ */
+
+static __u8 via_pram_readbyte(void)
+{
+	int	i,reg;
+	__u8	data;
+
+	reg = via1[vBufB] & ~VIA1B_vRTCClk;
+
+	/* Set the RTC data line to be an input. */
+
+	via1[vDirB] &= ~VIA1B_vRTCData;
+
+	/* The bits of the byte come out in MSB order */
+
+	data = 0;
+	for (i = 0 ; i < 8 ; i++) {
+		via1[vBufB] = reg;
+		via1[vBufB] = reg | VIA1B_vRTCClk;
+		data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
+	}
+
+	/* Return RTC data line to output state */
+
+	via1[vDirB] |= VIA1B_vRTCData;
+
+	return data;
+}
+
+static void via_pram_writebyte(__u8 data)
+{
+	int	i,reg,bit;
+
+	reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
+
+	/* The bits of the byte go in in MSB order */
+
+	for (i = 0 ; i < 8 ; i++) {
+		bit = data & 0x80? 1 : 0;
+		data <<= 1;
+		via1[vBufB] = reg | bit;
+		via1[vBufB] = reg | bit | VIA1B_vRTCClk;
+	}
+}
+
+/*
+ * Execute a VIA PRAM/RTC command. For read commands
+ * data should point to a one-byte buffer for the
+ * resulting data. For write commands it should point
+ * to the data byte to for the command.
+ *
+ * This function disables all interrupts while running.
+ */
+
+static void via_pram_command(int command, __u8 *data)
+{
+	unsigned long cpu_flags;
+	int	is_read;
+
+	save_flags(cpu_flags);
+	cli();
+
+	/* Enable the RTC and make sure the strobe line is high */
+
+	via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
+
+	if (command & 0xFF00) {		/* extended (two-byte) command */
+		via_pram_writebyte((command & 0xFF00) >> 8);
+		via_pram_writebyte(command & 0xFF);
+		is_read = command & 0x8000;
+	} else {			/* one-byte command */
+		via_pram_writebyte(command);
+		is_read = command & 0x80;
+	}
+	if (is_read) {
+		*data = via_pram_readbyte();
+	} else {
+		via_pram_writebyte(*data);
+	}
+
+	/* All done, disable the RTC */
+
+	via1[vBufB] |= VIA1B_vRTCEnb;
+
+	restore_flags(cpu_flags);
+}
+
+static __u8 via_read_pram(int offset)
+{
+	return 0;
+}
+
+static void via_write_pram(int offset, __u8 data)
+{
+}
+
+/*
+ * Return the current time in seconds since January 1, 1904.
+ *
+ * This only works on machines with the VIA-based PRAM/RTC, which
+ * is basically any machine with Mac II-style ADB.
+ */
+
+static long via_read_time(void)
+{
+	union {
+		__u8  cdata[4];
+		long  idata;
+	} result, last_result;
+	int	ct;
+
+	/*
+	 * The NetBSD guys say to loop until you get the same reading
+	 * twice in a row.
+	 */
+
+	ct = 0;
+	do {
+		if (++ct > 10) {
+			printk("via_read_time: couldn't get valid time, "
+			       "last read = 0x%08X and 0x%08X\n", last_result.idata,
+			       result.idata);
+			break;
+		}
+
+		last_result.idata = result.idata;
+		result.idata = 0;
+
+		via_pram_command(0x81, &result.cdata[3]);
+		via_pram_command(0x85, &result.cdata[2]);
+		via_pram_command(0x89, &result.cdata[1]);
+		via_pram_command(0x8D, &result.cdata[0]);
+	} while (result.idata != last_result.idata);
+
+	return result.idata - RTC_OFFSET;
+}
+
+/*
+ * Set the current time to a number of seconds since January 1, 1904.
+ *
+ * This only works on machines with the VIA-based PRAM/RTC, which
+ * is basically any machine with Mac II-style ADB.
+ */
+
+static void via_write_time(long time)
+{
+	union {
+		__u8  cdata[4];
+		long  idata;
+	} data;
+	__u8	temp;
+
+	/* Clear the write protect bit */
+
+	temp = 0x55;
+	via_pram_command(0x35, &temp);
+
+	data.idata = time + RTC_OFFSET;
+	via_pram_command(0x01, &data.cdata[3]);
+	via_pram_command(0x05, &data.cdata[2]);
+	via_pram_command(0x09, &data.cdata[1]);
+	via_pram_command(0x0D, &data.cdata[0]);
+
+	/* Set the write protect bit */
+
+	temp = 0xD5;
+	via_pram_command(0x35, &temp);
+}
+
+static void via_shutdown(void)
+{
+	if (rbv_present) {
+		via2[rBufB] &= ~0x04;
+	} else {
+		/* Direction of vDirB is output */
+		via2[vDirB] |= 0x04;
+		/* Send a value of 0 on that line */
+		via2[vBufB] &= ~0x04;
+		mdelay(1000);
+	}
+}
+
+/*
+ * FIXME: not sure how this is supposed to work exactly...
+ */
+
+static void oss_shutdown(void)
+{
+	oss->rom_ctrl = OSS_POWEROFF;
+}
+
+#ifdef CONFIG_ADB_CUDA
+
+static void cuda_restart(void)
+{
+	adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
+			2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+}
+
+static void cuda_shutdown(void)
+{
+	adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
+			2, CUDA_PACKET, CUDA_POWERDOWN);
+}
+
+#endif /* CONFIG_ADB_CUDA */
+
+#ifdef CONFIG_ADB_PMU
+
+void pmu_restart(void)
+{
+	adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
+			3, PMU_PACKET, PMU_SET_INTR_MASK,
+			PMU_INT_ADB|PMU_INT_TICK);
+	
+	adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
+			2, PMU_PACKET, PMU_RESET);
+}
+
+void pmu_shutdown(void)
+{
+	adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
+			3, PMU_PACKET, PMU_SET_INTR_MASK,
+			PMU_INT_ADB|PMU_INT_TICK);
+
+	adb_request(NULL, NULL, ADBREQ_RAW|ADBREQ_SYNC,
+			6, PMU_PACKET, PMU_SHUTDOWN,
+			'M', 'A', 'T', 'T');
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+/*
+ *-------------------------------------------------------------------
+ * Below this point are the generic routines; they'll dispatch to the
+ * correct routine for the hardware on which we're running.
+ *-------------------------------------------------------------------
+ */
+
+void mac_pram_read(int offset, __u8 *buffer, int len)
+{
+	__u8 (*func)(int) = NULL;
+	int i;
+
+	if (macintosh_config->adb_type == MAC_ADB_IISI ||
+	    macintosh_config->adb_type == MAC_ADB_PB1 ||
+	    macintosh_config->adb_type == MAC_ADB_PB2 ||
+	    macintosh_config->adb_type == MAC_ADB_CUDA) {
+		func = adb_read_pram;
+	} else {
+		func = via_read_pram;
+	}
+	for (i = 0 ; i < len ; i++) {
+		buffer[i] = (*func)(offset++);
+	}
+}
+
+void mac_pram_write(int offset, __u8 *buffer, int len)
+{
+	void (*func)(int, __u8) = NULL;
+	int i;
+
+	if (macintosh_config->adb_type == MAC_ADB_IISI ||
+	    macintosh_config->adb_type == MAC_ADB_PB1 ||
+	    macintosh_config->adb_type == MAC_ADB_PB2 ||
+	    macintosh_config->adb_type == MAC_ADB_CUDA) {
+		func = adb_write_pram;
+	} else {
+		func = via_write_pram;
+	}
+	for (i = 0 ; i < len ; i++) {
+		(*func)(offset++, buffer[i]);
+	}
+}
+
+void mac_poweroff(void)
+{
+	/*
+	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
+	 * work using the ADB packet method.  --David Kilzer
+	 */
+
+	if (oss_present) {
+		oss_shutdown();
+	} else if (macintosh_config->adb_type == MAC_ADB_II) {
+		via_shutdown();
+#ifdef CONFIG_ADB_CUDA
+	} else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
+		cuda_shutdown();
+#endif
+#ifdef CONFIG_ADB_PMU
+	} else if (macintosh_config->adb_type == MAC_ADB_PB1
+		|| macintosh_config->adb_type == MAC_ADB_PB2) {
+		pmu_shutdown();
+#endif
+	}
+	sti();
+	printk("It is now safe to turn off your Macintosh.\n");
+	while(1);
+}
+
+void mac_reset(void)
+{
+	if (macintosh_config->adb_type == MAC_ADB_II) {
+		unsigned long cpu_flags;
+
+		/* need ROMBASE in booter */
+		/* indeed, plus need to MAP THE ROM !! */
+
+		if (mac_bi_data.rombase == 0)
+			mac_bi_data.rombase = 0x40800000;
+
+		/* works on some */
+		rom_reset = (void *) (mac_bi_data.rombase + 0xa);
+
+		if (macintosh_config->ident == MAC_MODEL_SE30) {
+			/*
+			 * MSch: Machines known to crash on ROM reset ...
+			 */
+		} else {
+			save_flags(cpu_flags);
+			cli();
+
+			rom_reset();
+
+			restore_flags(cpu_flags);
+		}
+#ifdef CONFIG_ADB_CUDA
+	} else if (macintosh_config->adb_type == MAC_ADB_CUDA) {
+		cuda_restart();
+#endif
+#ifdef CONFIG_ADB_PMU
+	} else if (macintosh_config->adb_type == MAC_ADB_PB1
+		|| macintosh_config->adb_type == MAC_ADB_PB2) {
+		pmu_restart();
+#endif
+	} else if (CPU_IS_030) {
+
+		/* 030-specific reset routine.  The idea is general, but the
+		 * specific registers to reset are '030-specific.  Until I
+		 * have a non-030 machine, I can't test anything else.
+		 *  -- C. Scott Ananian <cananian@alumni.princeton.edu>
+		 */
+
+		unsigned long rombase = 0x40000000;
+
+		/* make a 1-to-1 mapping, using the transparent tran. reg. */
+		unsigned long virt = (unsigned long) mac_reset;
+		unsigned long phys = virt_to_phys(mac_reset);
+		unsigned long offset = phys-virt;
+		cli(); /* lets not screw this up, ok? */
+		__asm__ __volatile__(".chip 68030\n\t"
+				     "pmove %0,%/tt0\n\t"
+				     ".chip 68k"
+				     : : "m" ((phys&0xFF000000)|0x8777));
+		/* Now jump to physical address so we can disable MMU */
+		__asm__ __volatile__(
+                    ".chip 68030\n\t"
+		    "lea %/pc@(1f),%/a0\n\t"
+		    "addl %0,%/a0\n\t"/* fixup target address and stack ptr */
+		    "addl %0,%/sp\n\t" 
+		    "pflusha\n\t"
+		    "jmp %/a0@\n\t" /* jump into physical memory */
+		    "0:.long 0\n\t" /* a constant zero. */
+		    /* OK.  Now reset everything and jump to reset vector. */
+		    "1:\n\t"
+		    "lea %/pc@(0b),%/a0\n\t"
+		    "pmove %/a0@, %/tc\n\t" /* disable mmu */
+		    "pmove %/a0@, %/tt0\n\t" /* disable tt0 */
+		    "pmove %/a0@, %/tt1\n\t" /* disable tt1 */
+		    "movel #0, %/a0\n\t"
+		    "movec %/a0, %/vbr\n\t" /* clear vector base register */
+		    "movec %/a0, %/cacr\n\t" /* disable caches */
+		    "movel #0x0808,%/a0\n\t"
+		    "movec %/a0, %/cacr\n\t" /* flush i&d caches */
+		    "movew #0x2700,%/sr\n\t" /* set up status register */
+		    "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */
+		    "movec %/a0, %/isp\n\t" 
+		    "movel %1@(0x4),%/a0\n\t" /* load reset vector */
+		    "reset\n\t" /* reset external devices */
+		    "jmp %/a0@\n\t" /* jump to the reset vector */
+		    ".chip 68k"
+		    : : "r" (offset), "a" (rombase) : "a0");
+	}
+
+	/* should never get here */
+	sti();
+	printk ("Restart failed.  Please restart manually.\n");
+	while(1);
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static unsigned long mktime(unsigned int year, unsigned int mon,
+	unsigned int day, unsigned int hour,
+	unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+	      year*365 - 719499
+	    )*24 + hour /* now have hours */
+	   )*60 + min /* now have minutes */
+	  )*60 + sec; /* finally seconds */
+}
+
+/*
+ * This function translates seconds since 1970 into a proper date.
+ *
+ * Algorithm cribbed from glibc2.1, __offtime().
+ */
+#define SECS_PER_MINUTE (60)
+#define SECS_PER_HOUR  (SECS_PER_MINUTE * 60)
+#define SECS_PER_DAY   (SECS_PER_HOUR * 24)
+
+static void unmktime(unsigned long time, long offset,
+		     int *yearp, int *monp, int *dayp,
+		     int *hourp, int *minp, int *secp)
+{
+        /* How many days come before each month (0-12).  */
+	static const unsigned short int __mon_yday[2][13] =
+	{
+		/* Normal years.  */
+		{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+		/* Leap years.  */
+		{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+	};
+	long int days, rem, y, wday, yday;
+	const unsigned short int *ip;
+
+	days = time / SECS_PER_DAY;
+	rem = time % SECS_PER_DAY;
+	rem += offset;
+	while (rem < 0) {
+		rem += SECS_PER_DAY;
+		--days;
+	}
+	while (rem >= SECS_PER_DAY) {
+		rem -= SECS_PER_DAY;
+		++days;
+	}
+	*hourp = rem / SECS_PER_HOUR;
+	rem %= SECS_PER_HOUR;
+	*minp = rem / SECS_PER_MINUTE;
+	*secp = rem % SECS_PER_MINUTE;
+	/* January 1, 1970 was a Thursday. */
+	wday = (4 + days) % 7; /* Day in the week. Not currently used */
+	if (wday < 0) wday += 7;
+	y = 1970;
+
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+#define __isleap(year)	\
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+	while (days < 0 || days >= (__isleap (y) ? 366 : 365))
+	{
+		/* Guess a corrected year, assuming 365 days per year.  */
+		long int yg = y + days / 365 - (days % 365 < 0);
+
+		/* Adjust DAYS and Y to match the guessed year.  */
+		days -= ((yg - y) * 365
+			 + LEAPS_THRU_END_OF (yg - 1)
+			 - LEAPS_THRU_END_OF (y - 1));
+		y = yg;
+	}
+	*yearp = y - 1900;
+	yday = days; /* day in the year.  Not currently used. */
+	ip = __mon_yday[__isleap(y)];
+	for (y = 11; days < (long int) ip[y]; --y)
+		continue;
+	days -= ip[y];
+	*monp = y;
+	*dayp = days + 1; /* day in the month */
+	return;
+}
+
+/*
+ * Return the boot time for use in initializing the kernel clock.
+ *
+ * I'd like to read the hardware clock here but many machines read
+ * the PRAM through ADB, and interrupts aren't initialized when this
+ * is called so ADB obviously won't work.
+ */
+
+void mac_gettod(int *yearp, int *monp, int *dayp,
+	       int *hourp, int *minp, int *secp)
+{
+	/* Yes the GMT bias is backwards.  It looks like Penguin is
+           screwing up the boottime it gives us... This works for me
+           in Canada/Eastern but it might be wrong everywhere else. */
+	unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60,
+		yearp, monp, dayp, hourp, minp, secp);
+	/* For some reason this is off by one */
+	*monp = *monp + 1;
+}
+
+/* 
+ * Read/write the hardware clock.
+ */
+
+int mac_hwclk(int op, struct hwclk_time *t)
+{
+	unsigned long now;
+
+	if (!op) { /* read */
+		if (macintosh_config->adb_type == MAC_ADB_II) {
+			now = via_read_time();
+		} else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
+			   (macintosh_config->adb_type == MAC_ADB_PB1) ||
+			   (macintosh_config->adb_type == MAC_ADB_PB2) ||
+			   (macintosh_config->adb_type == MAC_ADB_CUDA)) {
+			now = adb_read_time();
+		} else if (macintosh_config->adb_type == MAC_ADB_IOP) {
+			now = via_read_time();
+		} else {
+			now = 0;
+		}
+
+		t->wday = 0;
+		unmktime(now, 0,
+			 &t->year, &t->mon, &t->day,
+			 &t->hour, &t->min, &t->sec);
+		printk("mac_hwclk: read %04d-%02d-%-2d %02d:%02d:%02d\n",
+			t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec);
+	} else { /* write */
+		printk("mac_hwclk: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n",
+			t->year + 1900, t->mon + 1, t->day, t->hour, t->min, t->sec);
+
+#if 0	/* it trashes my rtc */
+		now = mktime(t->year + 1900, t->mon + 1, t->day,
+			     t->hour, t->min, t->sec);
+
+		if (macintosh_config->adb_type == MAC_ADB_II) {
+			via_write_time(now);
+		} else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
+			   (macintosh_config->adb_type == MAC_ADB_PB1) ||
+			   (macintosh_config->adb_type == MAC_ADB_PB2) ||
+			   (macintosh_config->adb_type == MAC_ADB_CUDA)) {
+			adb_write_time(now);
+		} else if (macintosh_config->adb_type == MAC_ADB_IOP) {
+			via_write_time(now);
+		}
+#endif
+	}
+	return 0;
+}
+
+/*
+ * Set minutes/seconds in the hardware clock
+ */
+
+int mac_set_clock_mmss (unsigned long nowtime)
+{
+	struct hwclk_time now;
+
+	mac_hwclk(0, &now);
+	now.sec = nowtime % 60;
+	now.min = (nowtime / 60) % 60;
+	mac_hwclk(1, &now);
+
+	return 0;
+}
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/oss.c linux/arch/m68k/mac/oss.c
--- v2.3.44/linux/arch/m68k/mac/oss.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/oss.c	Sun Feb 13 11:21:42 2000
@@ -34,7 +34,7 @@
 void oss_nubus_irq(int, void *, struct pt_regs *);
 
 extern void via1_irq(int, void *, struct pt_regs *);
-extern void mac_SCC_handler(int, void *, struct pt_regs *);
+extern void mac_scc_dispatch(int, void *, struct pt_regs *);
 extern int console_loglevel;
 
 /*
@@ -68,16 +68,16 @@
 
 void __init oss_register_interrupts(void)
 {
-	request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
-		    "OSS SCSI Dispatch", (void *) oss);
-	request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK,
-		    "SCC Dispatch", mac_SCC_handler);
-	request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
-		    "Nubus Dispatch", (void *) oss);
-	request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
-		    "OSS Sound Dispatch", (void *) oss);
-	request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
-		    "VIA1 Dispatch", (void *) via1);
+	sys_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+			"scsi", (void *) oss);
+	sys_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK,
+			"scc", mac_scc_dispatch);
+	sys_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+			"nubus", (void *) oss);
+	sys_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+			"sound", (void *) oss);
+	sys_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+			"via1", (void *) via1);
 }
 
 /*
@@ -86,22 +86,6 @@
 
 void __init oss_nubus_init(void)
 {
-}
-
-/*
- * Turn off the power via the ROM control register
- *
- * FIXME: not sure how this is supposed to work exactly...
- */
-
-void oss_poweroff(void)
-{
-	oss->rom_ctrl = OSS_POWEROFF;
-
-	/* We should never make it this far... */
-
-	printk ("It is now safe to switch off your machine.\n");
-	while(1);
 }
 
 /*
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c
--- v2.3.44/linux/arch/m68k/mac/psc.c	Thu Nov 18 20:25:37 1999
+++ linux/arch/m68k/mac/psc.c	Sun Feb 13 11:21:42 2000
@@ -119,14 +119,14 @@
 
 void __init psc_register_interrupts(void)
 {
-	request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
-		    (void *) 0x30);
-	request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
-		    (void *) 0x40);
-	request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
-		    (void *) 0x50);
-	request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
-		    (void *) 0x60);
+	sys_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3",
+			(void *) 0x30);
+	sys_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4",
+			(void *) 0x40);
+	sys_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5",
+			(void *) 0x50);
+	sys_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6",
+			(void *) 0x60);
 }
 
 /*
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mac/via.c linux/arch/m68k/mac/via.c
--- v2.3.44/linux/arch/m68k/mac/via.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/via.c	Sun Feb 13 11:21:42 2000
@@ -24,6 +24,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 
+#include <linux/ide.h>
+
 #include <asm/traps.h>
 #include <asm/bootinfo.h> 
 #include <asm/macintosh.h> 
@@ -60,7 +62,7 @@
 #define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
 #define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
 
-static int  nubus_active;
+static int  nubus_active = 0;
 
 void via_debug_dump(void);
 void via1_irq(int, void *, struct pt_regs *);
@@ -71,7 +73,7 @@
 void via_irq_clear(int irq);
 
 extern void mac_bang(int, void *, struct pt_regs *);
-extern void mac_SCC_handler(int, void *, struct pt_regs *);
+extern void mac_scc_dispatch(int, void *, struct pt_regs *);
 extern int console_loglevel;
 extern int oss_present;
 
@@ -260,28 +262,28 @@
 void __init via_register_interrupts(void)
 {
 	if (via_alt_mapping) {
-		request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-			    "Software IRQ", (void *) via1);
-		request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-			    "VIA1 Dispatch", (void *) via1);
+		sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+				"software", (void *) via1);
+		sys_request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+				"via1", (void *) via1);
 	} else {
-		request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-			    "VIA1 Dispatch", (void *) via1);
+		sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+				"via1", (void *) via1);
 #if 0 /* interferes with serial on some machines */
 		if (!psc_present) {
-			request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
+			sys_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
 					"Off Switch", mac_bang);
 		}
 #endif
 	}
-	request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-		    "VIA2 Dispatch", (void *) via2);
+	sys_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+			"via2", (void *) via2);
 	if (!psc_present) {
-		request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK,
-			    "SCC Dispatch", mac_SCC_handler);
+		sys_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK,
+				"scc", mac_scc_dispatch);
 	}
 	request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
-			"Nubus Dispatch", (void *) via2);
+			"nubus", (void *) via2);
 }
 
 /*
@@ -361,34 +363,13 @@
 }
 
 /*
- * VIA-based power switch, for machines that support it.
- */
-
-void via_poweroff(void)
-{
-	if (rbv_present) {
-		via2[rBufB] &= ~0x04;
-	} else {
-		/* Direction of vDirB is output */
-		via2[vDirB] |= 0x04;
-		/* Send a value of 0 on that line */
-		via2[vBufB] &= ~0x04;
-		/* Otherwise it prints "It is now.." then shuts off */
-		mdelay(1000);
-	}
-
-	/* We should never make it this far... */
-	printk ("It is now safe to switch off your machine.\n");
-	while(1);
-}
-
-/*
  * Initialize VIA2 for Nubus access
  */
 
 void __init via_nubus_init(void)
 {
-	nubus_active = 0;
+	/* don't set nubus_active = 0 here, it kills the Baboon */
+	/* interrupt that we've already registered.		*/
 
 	/* unlock nubus transactions */
 
@@ -396,14 +377,22 @@
 		/* set the line to be an output on non-RBV machines */
 		via2[vDirB] |= 0x02;
 	}
-	via2[gBufB] |= 0x02;
+
+	/* this seems to be an ADB bit on PMU machines */
+	/* according to MkLinux.  -- jmt               */
+
+	if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+	    (macintosh_config->adb_type != MAC_ADB_PB2)) {
+		via2[gBufB] |= 0x02;
+	}
 
 	/* disable nubus slot interrupts. */
 	if (rbv_present) {
-		via2[rSIER] = 0x7F;	/* like VIA; bit 7=clr,set */
+		via2[rSIER] = 0x7F;
+		via2[rSIER] = nubus_active | 0x80;
 	} else {
-		via2[vBufA] = 0xFF;	/* active low irqs, force high */
-		via2[vDirA] = 0xFF;	/* ddr to output. */
+		via2[vBufA] = 0xFF;
+		via2[vDirA] = ~nubus_active;
 	}
 }
 
@@ -478,7 +467,7 @@
 	int irq_bit, i;
 	unsigned char events;
 
-	if (!(events = ~via2[gBufA]  & nubus_active)) return;
+	if (!(events = ~via2[gBufA] & nubus_active)) return;
 
 	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
 		if (events & irq_bit) {
@@ -586,189 +575,4 @@
 		return ~via2[gBufA] & irq_bit;
 	}
 	return 0;
-}
-
-void via_scsi_clear(void)
-{
-	volatile unsigned char deep_magic;
-
-#ifdef DEBUG_IRQUSE
-	printk("via_scsi_clear()\n");
-#endif
-
-	/* We handle this in oss.c , but this gets called in mac_scsinew.c */
-	if(oss_present) return;
-
-	if (rbv_present) {
-		via2[rIFR] = (1<<3) | (1<<0) | rbv_clear;
-		deep_magic = via2[rBufB];
-	} else {
-		deep_magic = via2[vBufB];
-	}
-	mac_enable_irq(IRQ_MAC_SCSI);
-}
-
-/*
- * PRAM/RTC access routines
- *
- * Must be called with interrupts disabled and
- * the RTC should be enabled.
- */
-
-static __u8 via_pram_readbyte(void)
-{
-	int	i,reg;
-	__u8	data;
-
-	reg = via1[vBufB] & ~VIA1B_vRTCClk;
-
-	/* Set the RTC data line to be an input. */
-
-	via1[vDirB] &= ~VIA1B_vRTCData;
-
-	/* The bits of the byte come out in MSB order */
-
-	data = 0;
-	for (i = 0 ; i < 8 ; i++) {
-		via1[vBufB] = reg;
-		via1[vBufB] = reg | VIA1B_vRTCClk;
-		data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
-	}
-
-	/* Return RTC data line to output state */
-
-	via1[vDirB] |= VIA1B_vRTCData;
-
-	return data;
-}
-
-static void via_pram_writebyte(__u8 data)
-{
-	int	i,reg,bit;
-
-	reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
-
-	/* The bits of the byte go in in MSB order */
-
-	for (i = 0 ; i < 8 ; i++) {
-		bit = data & 0x80? 1 : 0;
-		data <<= 1;
-		via1[vBufB] = reg | bit;
-		via1[vBufB] = reg | bit | VIA1B_vRTCClk;
-	}
-}
-
-/*
- * Execute a PRAM/RTC command. For read commands
- * data should point to a one-byte buffer for the
- * resulting data. For write commands it should point
- * to the data byte to for the command.
- *
- * This function disables all interrupts while running.
- */
-
-void via_pram_command(int command, __u8 *data)
-{
-	unsigned long cpu_flags;
-	int	is_read;
-
-	save_flags(cpu_flags);
-	cli();
-
-	/* Enable the RTC and make sure the strobe line is high */
-
-	via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
-
-	if (command & 0xFF00) {		/* extended (two-byte) command */
-		via_pram_writebyte((command & 0xFF00) >> 8);
-		via_pram_writebyte(command & 0xFF);
-		is_read = command & 0x8000;
-	} else {			/* one-byte command */
-		via_pram_writebyte(command);
-		is_read = command & 0x80;
-	}
-	if (is_read) {
-		*data = via_pram_readbyte();
-	} else {
-		via_pram_writebyte(*data);
-	}
-
-	/* All done, disable the RTC */
-
-	via1[vBufB] |= VIA1B_vRTCEnb;
-
-	restore_flags(cpu_flags);
-}
-
-/*
- * Return the current time in seconds since January 1, 1904.
- *
- * This only works on machines with the VIA-based PRAM/RTC, which
- * is basically any machine with Mac II-style ADB.
- */
-
-__u32 via_read_time(void)
-{
-	union {
-		__u8  cdata[4];
-		__u32 idata;
-	} result, last_result;
-	int	ct;
-
-	/*
-	 * The NetBSD guys say to loop until you get the same reading
-	 * twice in a row.
-	 */
-
-	ct = 0;
-	do {
-		if (++ct > 10) {
-			printk("via_read_time: couldn't get valid time, "
-			       "last read = 0x%08X and 0x%08X\n", last_result.idata,
-			       result.idata);
-			break;
-		}
-
-		last_result.idata = result.idata;
-		result.idata = 0;
-
-		via_pram_command(0x81, &result.cdata[3]);
-		via_pram_command(0x85, &result.cdata[2]);
-		via_pram_command(0x89, &result.cdata[1]);
-		via_pram_command(0x8D, &result.cdata[0]);
-	} while (result.idata != last_result.idata);
-
-	return result.idata;
-}
-
-/*
- * Set the current time to a number of seconds since January 1, 1904.
- *
- * This only works on machines with the VIA-based PRAM/RTC, which
- * is basically any machine with Mac II-style ADB.
- */
-
-void via_write_time(__u32 time)
-{
-	union {
-		__u8  cdata[4];
-		__u32 idata;
-	} data;
-	__u8	temp;
-
-	/* Clear the write protect bit */
-
-	temp = 0x55;
-	via_pram_command(0x35, &temp);
-
-	data.idata = time;
-	via_pram_command(0x01, &data.cdata[3]);
-	via_pram_command(0x05, &data.cdata[2]);
-	via_pram_command(0x09, &data.cdata[1]);
-	via_pram_command(0x0D, &data.cdata[0]);
-
-	/* Set the write protect bit */
-
-	temp = 0xD5;
-	via_pram_command(0x35, &temp);
 }
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mm/motorola.c linux/arch/m68k/mm/motorola.c
--- v2.3.44/linux/arch/m68k/mm/motorola.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/mm/motorola.c	Sun Feb 13 11:21:42 2000
@@ -207,7 +207,7 @@
 {
 	int chunk;
 	unsigned long mem_avail = 0;
-	unsigned int zones_size[3] = { 0, };
+	unsigned long zones_size[3] = { 0, };
 
 #ifdef DEBUG
 	{
diff -u --recursive --new-file v2.3.44/linux/arch/m68k/mm/sun3mmu.c linux/arch/m68k/mm/sun3mmu.c
--- v2.3.44/linux/arch/m68k/mm/sun3mmu.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/mm/sun3mmu.c	Sun Feb 13 11:21:42 2000
@@ -30,7 +30,7 @@
 
 extern void mmu_emu_init (void);
 
-extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long free_area_init(unsigned long *zones_size);
 
 const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
 
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/coffboot/misc.S linux/arch/ppc/coffboot/misc.S
--- v2.3.44/linux/arch/ppc/coffboot/misc.S	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/coffboot/misc.S	Sun Feb 13 10:47:01 2000
@@ -9,7 +9,7 @@
 	.text
 
 /*
- * Use the BAT0 registers to map the 1st 8MB of RAM to
+ * Use the BAT3 registers to map the 1st 8MB of RAM to
  * the address given as the 1st argument.
  */
 	.globl	setup_bats
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig
--- v2.3.44/linux/arch/ppc/configs/common_defconfig	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/configs/common_defconfig	Sun Feb 13 10:47:01 2000
@@ -24,7 +24,7 @@
 # CONFIG_GEMINI is not set
 # CONFIG_APUS is not set
 # CONFIG_SMP is not set
-# CONFIG_ALTIVEC is not set
+CONFIG_ALTIVEC=y
 
 #
 # Loadable module support
@@ -76,7 +76,7 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -178,9 +178,12 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
+CONFIG_ST_EXTRA_DEVS=2
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
 
 #
@@ -239,6 +242,7 @@
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -275,6 +279,7 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+CONFIG_GMAC=y
 # CONFIG_NCR885E is not set
 # CONFIG_OAKNET is not set
 # CONFIG_NET_VENDOR_3COM is not set
@@ -472,6 +477,7 @@
 # USB Controllers
 #
 # CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
 
 #
@@ -491,8 +497,7 @@
 # CONFIG_USB_IBMCAM is not set
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_DC2XX is not set
-CONFIG_USB_SCSI=m
-CONFIG_USB_SCSI_DEBUG=y
+# CONFIG_USB_STORAGE is not set
 # CONFIG_USB_DABUSB is not set
 
 #
@@ -513,11 +518,15 @@
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
+CONFIG_HFS_FS=y
 # CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_ISO9660_FS=y
@@ -549,10 +558,51 @@
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
 CONFIG_MAC_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
 
 #
 # Sound
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig
--- v2.3.44/linux/arch/ppc/configs/gemini_defconfig	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/configs/gemini_defconfig	Sun Feb 13 10:47:01 2000
@@ -24,7 +24,7 @@
 CONFIG_GEMINI=y
 # CONFIG_APUS is not set
 # CONFIG_SMP is not set
-# CONFIG_ALTIVEC is not set
+CONFIG_ALTIVEC=y
 CONFIG_MACH_SPECIFIC=y
 
 #
@@ -87,7 +87,6 @@
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -151,9 +150,12 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
 # CONFIG_CHR_DEV_ST is not set
+CONFIG_ST_EXTRA_DEVS=2
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
 # CONFIG_CHR_DEV_SG is not set
 
 #
@@ -208,6 +210,7 @@
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -216,6 +219,7 @@
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -242,6 +246,7 @@
 CONFIG_NET_ETHERNET=y
 # CONFIG_MACE is not set
 # CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
 CONFIG_NCR885E=y
 # CONFIG_OAKNET is not set
 # CONFIG_NET_VENDOR_3COM is not set
@@ -369,6 +374,7 @@
 #
 # CONFIG_QUOTA is not set
 # CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -405,10 +411,7 @@
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MAC_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.44/linux/arch/ppc/defconfig	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/defconfig	Sun Feb 13 10:47:01 2000
@@ -24,7 +24,7 @@
 # CONFIG_GEMINI is not set
 # CONFIG_APUS is not set
 # CONFIG_SMP is not set
-# CONFIG_ALTIVEC is not set
+CONFIG_ALTIVEC=y
 
 #
 # Loadable module support
@@ -76,7 +76,7 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -178,9 +178,12 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
+CONFIG_ST_EXTRA_DEVS=2
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
 
 #
@@ -239,6 +242,7 @@
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -275,6 +279,7 @@
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
+CONFIG_GMAC=y
 # CONFIG_NCR885E is not set
 # CONFIG_OAKNET is not set
 # CONFIG_NET_VENDOR_3COM is not set
@@ -472,6 +477,7 @@
 # USB Controllers
 #
 # CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
 CONFIG_USB_OHCI=y
 
 #
@@ -491,8 +497,7 @@
 # CONFIG_USB_IBMCAM is not set
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_DC2XX is not set
-CONFIG_USB_SCSI=m
-CONFIG_USB_SCSI_DEBUG=y
+# CONFIG_USB_STORAGE is not set
 # CONFIG_USB_DABUSB is not set
 
 #
@@ -513,11 +518,15 @@
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
+CONFIG_HFS_FS=y
 # CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_ISO9660_FS=y
@@ -549,10 +558,51 @@
 #
 # Partition Types
 #
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
 CONFIG_MAC_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
 
 #
 # Sound
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.3.44/linux/arch/ppc/kernel/entry.S	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/entry.S	Sun Feb 13 10:47:01 2000
@@ -176,7 +176,7 @@
 7:	.string	"syscall %d(%x, %x, %x, %x, %x, "
 77:	.string	"%x, %x), current=%p\n"
 79:	.string	" -> %x\n"
-	.align	2
+	.align	2,0
 #endif
 
 /*
@@ -209,6 +209,9 @@
 	mflr	r20		/* Return to switch caller */
 	mfmsr	r22
 	li	r0,MSR_FP	/* Disable floating-point */
+#ifdef CONFIG_ALTIVEC
+	oris	r0,r0,MSR_VEC@h
+#endif /* CONFIG_ALTIVEC */
 	andc	r22,r22,r0
 	stw	r20,_NIP(r1)
 	stw	r22,_MSR(r1)
@@ -274,7 +277,7 @@
 	SYNC
 	rfi
 
-#ifdef __SMP__	
+#ifdef CONFIG_SMP	
 	.globl	ret_from_smpfork
 ret_from_smpfork:
 	bl	schedule_tail
@@ -310,22 +313,32 @@
 	lwz	r5,_MSR(r1)
 	andi.	r5,r5,MSR_EE
 	beq	2f
+	.globl	lost_irq_ret
+lost_irq_ret:
 3:	lis	r4,ppc_n_lost_interrupts@ha
 	lwz	r4,ppc_n_lost_interrupts@l(r4)
 	cmpi	0,r4,0
 	beq+	1f
 	addi	r3,r1,STACK_FRAME_OVERHEAD
 	bl	do_IRQ
-	.globl	lost_irq_ret
-lost_irq_ret:
 	b	3b
-1:	lis	r4,bh_mask@ha
-	lwz	r4,bh_mask@l(r4)
-	lis	r5,bh_active@ha
-	lwz	r5,bh_active@l(r5)
-	and.	r4,r4,r5
+1:	lis	r4,softirq_state@ha
+	addi	r4,r4,softirq_state@l
+#ifdef CONFIG_SMP
+	/* get processor # */
+	lwz	r3,PROCESSOR(r2)
+#ifndef CONFIG_PPC64
+	slwi	r3,r3,5
+#else
+#error not 64-bit ready	
+#endif
+	add	r4,r4,r3
+#endif /* CONFIG_SMP */
+	lwz	r5,0(r4)
+	lwz	r4,4(r4)
+	and.	r5,r5,r4
 	beq+	2f
-	bl	do_bottom_half
+	bl	do_softirq
 	.globl	do_bottom_half_ret
 do_bottom_half_ret:
 2:	/* disable interrupts */	
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.44/linux/arch/ppc/kernel/head.S	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/head.S	Sun Feb 13 10:47:01 2000
@@ -460,8 +460,24 @@
 	STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
 
 	STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
-#ifdef CONFIG_ALTIVEC	
-	STD_EXCEPTION(0xf20, AltiVec, AltiVecUnavailable)
+#ifndef CONFIG_ALTIVEC
+	STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
+#else	
+/*
+ * The Altivec unavailable trap is at 0x0f20.  Foo.
+ * We effectively remap it to 0x3000.
+ */
+	. = 0xf00
+	b	Trap_0f
+trap_0f_cont:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler
+	.long	UnknownException
+	.long	ret_from_except
+
+	. = 0xf20
+	b	AltiVecUnavailable
 #endif /* CONFIG_ALTIVEC */
 
 /*
@@ -674,6 +690,21 @@
 
 	. = 0x3000
 
+#ifdef CONFIG_ALTIVEC
+AltiVecUnavailable:
+	EXCEPTION_PROLOG
+	bne	load_up_altivec		/* if from user, just load it up */
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler	/* if from kernel, take a trap */
+	.long	KernelAltiVec
+	.long	ret_from_except
+
+/* here are the bits of trap 0xf00 which got displaced */
+Trap_0f:
+	EXCEPTION_PROLOG
+	b	trap_0f_cont
+#endif /* CONFIG_ALTIVEC */
+	
 /*
  * This code finishes saving the registers to the exception frame
  * and jumps to the appropriate handler for the exception, turning
@@ -813,72 +844,134 @@
 86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
 	.align	4
 
+#ifdef CONFIG_ALTIVEC
+/* Note that the AltiVec support is closely modeled after the FP
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_altivec:
 /*
- * Take away the altivec regs.
- *
- * For now, ignore the vrsave regs and save them all
- *   -- Cort
+ * Disable AltiVec for the task which had AltiVec previously,
+ * and save its AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ * On SMP we know the AltiVec units are free, since we give it up every
+ * switch.  -- Kumar
  */
-	.globl giveup_altivec
-giveup_altivec:
-#ifdef CONFIG_ALTIVEC	
-	/* check for altivec */
-	mfspr	r4,PVR
-	srwi	r4,r4,16
-	cmpi	0,r4,12
-	bnelr
-	
-	/* enable altivec so we can save */
-	mfmsr	r4
-	oris	r4,r4,MSR_VEC@h
-	mtmsr	r4
+	mfmsr	r5
+	oris	r5,r5,MSR_VEC@h
+	SYNC
+	mtmsr	r5			/* enable use of AltiVec now */
+	SYNC
+/*
+ * For SMP, we don't do lazy AltiVec switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_altivec in switch_to.
+ */
+#ifndef __SMP__
+#ifndef CONFIG_APUS
+	lis	r6,-KERNELBASE@h
+#else
+	lis	r6,CYBERBASEp@h
+	lwz	r6,0(r6)
+#endif
+	addis	r3,r6,last_task_used_altivec@ha
+	lwz	r4,last_task_used_altivec@l(r3)
+	cmpi	0,r4,0
+	beq	1f
+	add	r4,r4,r6
+	addi	r4,r4,THREAD	/* want THREAD of last_task_used_altivec */
+	SAVE_32VR(0,r20,r4)
+	MFVSCR(vr0)
+	li	r20,THREAD_VSCR
+	STVX(vr0,r20,r4)
+	lwz	r5,PT_REGS(r4)
+	add	r5,r5,r6
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r20,MSR_VEC@h
+	andc	r4,r4,r20	/* disable altivec for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* __SMP__ */
+	/* enable use of AltiVec after return */
+	oris	r23,r23,MSR_VEC@h
+	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
+	li	r20,THREAD_VSCR
+	LVX(vr0,r20,r5)
+	MTVSCR(vr0)
+	REST_32VR(0,r20,r5)
+#ifndef __SMP__
+	subi	r4,r5,THREAD
+	sub	r4,r4,r6
+	stw	r4,last_task_used_altivec@l(r3)
+#endif /* __SMP__ */
+	/* restore registers and return */
+	lwz	r3,_CCR(r21)
+	lwz	r4,_LINK(r21)
+	mtcrf	0xff,r3
+	mtlr	r4
+	REST_GPR(1, r21)
+	REST_4GPRS(3, r21)
+	/* we haven't used ctr or xer */
+	mtspr	SRR1,r23
+	mtspr	SRR0,r22
+	REST_GPR(20, r21)
+	REST_2GPRS(22, r21)
+	lwz	r21,GPR21(r21)
+	SYNC
+	rfi
 
-	/* make sure our tsk pointer is valid */
-	cmpi	0,r3,0
-	beqlr
+/*
+ * AltiVec unavailable trap from kernel - print a message, but let
+ * the task use AltiVec in the kernel until it returns to user mode.
+ */
+KernelAltiVec:
+	lwz	r3,_MSR(r1)
+	oris	r3,r3,MSR_VEC@h
+	stw	r3,_MSR(r1)	/* enable use of AltiVec after return */
+	lis	r3,87f@h
+	ori	r3,r3,87f@l
+	mr	r4,r2		/* current */
+	lwz	r5,_NIP(r1)
+	bl	printk
+	b	ret_from_except
+87:	.string	"AltiVec used in kernel  (task=%p, pc=%x)  \n"
+	.align	4
 
-	/* save altivec regs */
-	addi	r4,r3,THREAD+THREAD_VRSAVE
-	mfspr	r5,256		/* vrsave */
-	stw	r5,0(r4)
-	
-	/* get regs for the task */
-	addi	r4,r3,THREAD+PT_REGS
-	/* turn off the altivec bit in the tasks regs */
-	lwz	r5,_MSR(r4)
-	lis	r6,MSR_VEC@h
-	andi.	r5,r5,r6
-	stw	r5,_MSR(r4)
+/*
+ * giveup_altivec(tsk)
+ * Disable AltiVec for the task given as the argument,
+ * and save the AltiVec registers in its thread_struct.
+ * Enables AltiVec for use in the kernel on return.
+ */
 
-	/* we've given up the altivec - clear the pointer */
-	li	r3,0
-	lis	r4,last_task_used_altivec@h
-	stw	r3,last_task_used_altivec@l(r4)
-#endif /* CONFIG_ALTIVEC */
-	blr
-	
-	.globl load_up_altivec
-load_up_altivec:
-#ifdef CONFIG_ALTIVEC	
-	/* check for altivec */
-	mfspr	r4,PVR
-	srwi	r4,r4,16
-	cmpi	0,r4,12
-	bnelr
-	
-	/* restore altivec regs */
-	addi	r4,r3,THREAD+THREAD_VRSAVE
-	lwz	r5,0(r4)
-	mtspr	256,r5		/* vrsave */
-	
-	/* get regs for the task */
-	addi	r4,r3,THREAD+PT_REGS
-	/* turn on the altivec bit in the tasks regs */
-	lwz	r5,_MSR(r4)
+	.globl	giveup_altivec
+giveup_altivec:
+	mfmsr	r5
 	oris	r5,r5,MSR_VEC@h
-	stw	r5,_MSR(r4)
-#endif /* CONFIG_ALTIVEC */
+	SYNC
+	mtmsr	r5			/* enable use of AltiVec now */
+	SYNC
+	cmpi	0,r3,0
+	beqlr-				/* if no previous owner, done */
+	addi	r3,r3,THREAD		/* want THREAD of task */
+	lwz	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32VR(0, r4, r3)
+	MFVSCR(vr0)
+	li	r4,THREAD_VSCR
+	STVX(vr0, r4, r3)
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r3,MSR_VEC@h
+	andc	r4,r4,r3		/* disable AltiVec for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef __SMP__
+	li	r5,0
+	lis	r4,last_task_used_altivec@ha
+	stw	r5,last_task_used_altivec@l(r4)
+#endif /* __SMP__ */
 	blr
+#endif /* CONFIG_ALTIVEC */
 	
 /*
  * giveup_fpu(tsk)
@@ -1437,17 +1530,16 @@
 
 #if 0 /* That's useful debug stuff */
 setup_screen_bat:
+	li	r3,0
+	mtspr	DBAT1U,r3
+	mtspr	IBAT1U,r3
 	lis	r3, 0x9100
-#ifdef __SMP__
-	ori	r3,r3,0x12
-#else
-	ori	r3,r3,0x2
-#endif
-	mtspr	DBAT1L, r3
-	mtspr	IBAT1L, r3
+	ori	r4,r3,0x2a
+	mtspr	DBAT1L,r4
+	mtspr	IBAT1L,r4
 	ori	r3,r3,(BL_8M<<2)|0x2	/* set up BAT registers for 604 */
-	mtspr	DBAT1U, r3
-	mtspr	IBAT1U, r3
+	mtspr	DBAT1U,r3
+	mtspr	IBAT1U,r3
 	blr
 #endif
 	
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.44/linux/arch/ppc/kernel/irq.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/irq.c	Sun Feb 13 10:47:01 2000
@@ -74,8 +74,8 @@
 
 irq_desc_t irq_desc[NR_IRQS];
 int ppc_spurious_interrupts = 0;
-unsigned int ppc_local_bh_count[NR_CPUS];
-unsigned int ppc_local_irq_count[NR_CPUS];
+unsigned int local_bh_count[NR_CPUS];
+unsigned int 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];
@@ -350,7 +350,6 @@
 atomic_t global_irq_count;
 
 atomic_t global_bh_count;
-atomic_t global_bh_lock;
 
 static void show(char * str)
 {
@@ -361,12 +360,12 @@
 	printk("\n%s, CPU %d:\n", str, cpu);
 	printk("irq:  %d [%d %d]\n",
 	       atomic_read(&global_irq_count),
-	       ppc_local_irq_count[0],
-	       ppc_local_irq_count[1]);
+	       local_irq_count[0],
+	       local_irq_count[1]);
 	printk("bh:   %d [%d %d]\n",
 	       atomic_read(&global_bh_count),
-	       ppc_local_bh_count[0],
-	       ppc_local_bh_count[1]);
+	       local_bh_count[0],
+	       local_bh_count[1]);
 	stack = (unsigned long *) &str;
 	for (i = 40; i ; i--) {
 		unsigned long x = *++stack;
@@ -401,7 +400,7 @@
 		 * already executing in one..
 		 */
 		if (!atomic_read(&global_irq_count)) {
-			if (ppc_local_bh_count[cpu]
+			if (local_bh_count[cpu]
 			    || !atomic_read(&global_bh_count))
 				break;
 		}
@@ -423,7 +422,7 @@
 				continue;
 			if (global_irq_lock)
 				continue;
-			if (!ppc_local_bh_count[cpu]
+			if (!local_bh_count[cpu]
 			    && atomic_read(&global_bh_count))
 				continue;
 			if (!test_and_set_bit(0,&global_irq_lock))
@@ -514,7 +513,7 @@
 	if (flags & (1 << 15)) {
 		int cpu = smp_processor_id();
 		__cli();
-		if (!ppc_local_irq_count[cpu])
+		if (!local_irq_count[cpu])
 			get_irqlock(cpu);
 	}
 }
@@ -523,7 +522,7 @@
 {
 	int cpu = smp_processor_id();
 
-	if (!ppc_local_irq_count[cpu])
+	if (!local_irq_count[cpu])
 		release_irqlock(cpu);
 	__sti();
 }
@@ -547,7 +546,7 @@
 	retval = 2 + local_enabled;
 
 	/* check for global flags if we're not in an interrupt */
-	if (!ppc_local_irq_count[smp_processor_id()]) {
+	if (!local_irq_count[smp_processor_id()]) {
 		if (local_enabled)
 			retval = 1;
 		if (global_irq_holder == (unsigned char) smp_processor_id())
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.44/linux/arch/ppc/kernel/misc.S	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/misc.S	Sun Feb 13 10:47:01 2000
@@ -272,6 +272,38 @@
 	blr
 
 /*
+ * Copy a whole page.  We use the dcbz instruction on the destination
+ * to reduce memory traffic (it eliminates the unnecessary reads of
+ * the destination into cache).  This requires that the destination
+ * is cacheable.
+ */
+_GLOBAL(copy_page)
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+	addi	r3,r3,-4
+	addi	r4,r4,-4
+	li	r5,4
+1:	dcbz	r5,r3
+	lwz	r6,4(r4)
+	lwz	r7,8(r4)
+	lwz	r8,12(r4)
+	lwzu	r9,16(r4)
+	stw	r6,4(r3)
+	stw	r7,8(r3)
+	stw	r8,12(r3)
+	stwu	r9,16(r3)
+	lwz	r6,4(r4)
+	lwz	r7,8(r4)
+	lwz	r8,12(r4)
+	lwzu	r9,16(r4)
+	stw	r6,4(r3)
+	stw	r7,8(r3)
+	stw	r8,12(r3)
+	stwu	r9,16(r3)
+	bdnz	1b
+	blr
+
+/*
  * Atomic [test&set] exchange
  *
  *	unsigned long xchg_u32(void *ptr, unsigned long val)
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.3.44/linux/arch/ppc/kernel/mk_defs.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/mk_defs.c	Sun Feb 13 10:47:01 2000
@@ -48,9 +48,11 @@
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
-	DEFINE(THREAD_VRF, offsetof(struct thread_struct, vrf));
-	DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
+#ifdef CONFIG_ALTIVEC
+	DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0]));
 	DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
+	DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
+#endif /* CONFIG_ALTIVEC */
 	/* Interrupt register frame */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.3.44/linux/arch/ppc/kernel/open_pic.c	Thu Feb 10 17:11:04 2000
+++ linux/arch/ppc/kernel/open_pic.c	Sun Feb 13 10:47:01 2000
@@ -279,7 +279,7 @@
 		/* Initialize the spurious interrupt */
 		if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd);
 		openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
-		if ( !(_machine && (_MACH_gemini|_MACH_Pmac)) )
+		if ( !(_machine & (_MACH_gemini|_MACH_Pmac)) )
 		{
 			if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
 					"82c59 cascade", NULL))
@@ -490,7 +490,7 @@
 	/* make sure mask gets to controller before we return to user */
 	do {
 		mb(); /* sync is probably useless here */
-	} while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+	} while(openpic_readfield(&ISU[irq - open_pic_irq_offset].Vector_Priority,
 			OPENPIC_MASK));
 }
 
@@ -501,7 +501,7 @@
 	/* make sure mask gets to controller before we return to user */
 	do {
 		mb();  /* sync is probably useless here */
-	} while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+	} while(!openpic_readfield(&ISU[irq - open_pic_irq_offset].Vector_Priority,
     			OPENPIC_MASK));
 }
 
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.3.44/linux/arch/ppc/kernel/pmac_pic.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/pmac_pic.c	Sun Feb 13 10:47:01 2000
@@ -31,8 +31,6 @@
 static int max_real_irqs;
 static int has_openpic = 0;
 
-#define MAXCOUNT 10000000
-
 #define GATWICK_IRQ_POOL_SIZE        10
 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
 
@@ -186,25 +184,6 @@
 #endif
 		smp_message_recv();
 		return -2;	/* ignore, already handled */
-        }
-
-        {
-                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__ */
 
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.44/linux/arch/ppc/kernel/pmac_setup.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/pmac_setup.c	Sun Feb 13 10:47:01 2000
@@ -60,6 +60,7 @@
 #include <asm/machdep.h>
 #include <asm/keyboard.h>
 #include <asm/dma.h>
+#include <asm/bootx.h>
 
 #include "time.h"
 #include "local_irq.h"
@@ -440,6 +441,7 @@
 {
 	char *p;
 	int n;
+	kdev_t __init pmac_find_ide_boot(char *bootdevice, int n);
 
 	if (bootdevice == NULL)
 		return 0;
@@ -695,9 +697,12 @@
 #ifdef CONFIG_BOOTX_TEXT
 extern void drawchar(char c);
 extern void drawstring(const char *c);
+extern boot_infos_t *disp_bi;
 void
 pmac_progress(char *s, unsigned short hex)
 {
+	if (disp_bi == 0)
+		return;
 	drawstring(s);
 	drawchar('\n');
 }
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- v2.3.44/linux/arch/ppc/kernel/pmac_time.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/pmac_time.c	Sun Feb 13 10:47:01 2000
@@ -71,8 +71,8 @@
 		if (req.reply_len != 7)
 			printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
 			       req.reply_len);
-		return (unsigned long)(req.reply[1] << 24) + (req.reply[2] << 16)
-			+ (req.reply[3] << 8) + (unsigned long)req.reply[4] - RTC_OFFSET;
+		return (req.reply[3] << 24) + (req.reply[4] << 16)
+			+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
 #endif /* CONFIG_ADB_CUDA */
 #ifdef CONFIG_ADB_PMU
 	case SYS_CTRLER_PMU:
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h
--- v2.3.44/linux/arch/ppc/kernel/ppc_asm.h	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/ppc_asm.h	Sun Feb 13 10:47:01 2000
@@ -44,6 +44,28 @@
 #define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
 
+/*
+ * Once a version of gas that understands the AltiVec instructions
+ * is freely available, we can do this the normal way...  - paulus
+ */
+#define LVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(103<<1)
+#define STVX(r,a,b)	.long	(31<<26)+((r)<<21)+((a)<<16)+((b)<<11)+(231<<1)
+#define MFVSCR(r)	.long	(4<<26)+((r)<<21)+(1540<<1)
+#define MTVSCR(r)	.long	(4<<26)+((r)<<11)+(802<<1)
+
+#define SAVE_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); STVX(n,b,base)
+#define SAVE_2VR(n,b,base)	SAVE_VR(n,b,base); SAVE_VR(n+1,b,base) 
+#define SAVE_4VR(n,b,base)	SAVE_2VR(n,b,base); SAVE_2VR(n+2,b,base) 
+#define SAVE_8VR(n,b,base)	SAVE_4VR(n,b,base); SAVE_4VR(n+4,b,base) 
+#define SAVE_16VR(n,b,base)	SAVE_8VR(n,b,base); SAVE_8VR(n+8,b,base)
+#define SAVE_32VR(n,b,base)	SAVE_16VR(n,b,base); SAVE_16VR(n+16,b,base)
+#define REST_VR(n,b,base)	li b,THREAD_VR0+(16*(n)); LVX(n,b,base)
+#define REST_2VR(n,b,base)	REST_VR(n,b,base); REST_VR(n+1,b,base) 
+#define REST_4VR(n,b,base)	REST_2VR(n,b,base); REST_2VR(n+2,b,base) 
+#define REST_8VR(n,b,base)	REST_4VR(n,b,base); REST_4VR(n+4,b,base) 
+#define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base) 
+#define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
+
 #define SYNC \
 	sync; \
 	isync
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl
--- v2.3.44/linux/arch/ppc/kernel/ppc_asm.tmpl	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/ppc_asm.tmpl	Sun Feb 13 10:47:01 2000
@@ -80,3 +80,36 @@
 #define	fr29	29
 #define	fr30	30
 #define	fr31	31
+
+#define	vr0	0
+#define	vr1	1
+#define	vr2	2
+#define	vr3	3
+#define	vr4	4
+#define	vr5	5
+#define	vr6	6
+#define	vr7	7
+#define	vr8	8
+#define	vr9	9
+#define	vr10	10
+#define	vr11	11
+#define	vr12	12
+#define	vr13	13
+#define	vr14	14
+#define	vr15	15
+#define	vr16	16
+#define	vr17	17
+#define	vr18	18
+#define	vr19	19
+#define	vr20	20
+#define	vr21	21
+#define	vr22	22
+#define	vr23	23
+#define	vr24	24
+#define	vr25	25
+#define	vr26	26
+#define	vr27	27
+#define	vr28	28
+#define	vr29	29
+#define	vr30	30
+#define	vr31	31
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.44/linux/arch/ppc/kernel/ppc_ksyms.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Sun Feb 13 10:47:01 2000
@@ -72,8 +72,8 @@
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
-EXPORT_SYMBOL(ppc_local_irq_count);
-EXPORT_SYMBOL(ppc_local_bh_count);
+EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
 #ifdef __SMP__
 EXPORT_SYMBOL(kernel_flag);
 #endif /* __SMP__ */
@@ -272,4 +272,3 @@
 EXPORT_SYMBOL(decrementer_count);
 EXPORT_SYMBOL(get_wchan);
 EXPORT_SYMBOL(console_drivers);
-EXPORT_SYMBOL(do_bottom_half);
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.44/linux/arch/ppc/kernel/process.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/process.c	Sun Feb 13 10:47:01 2000
@@ -140,15 +140,31 @@
 }
 #endif /* defined(CHECK_STACK) */
 
+#ifdef CONFIG_ALTIVEC
 int
-dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+dump_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
 {
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+	memcpy(vrregs, &current->thread.vr[0], sizeof(*vrregs));
 	return 1;
 }
 
+void 
+enable_kernel_altivec(void)
+{
+#ifdef __SMP__
+	if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
+		giveup_altivec(current);
+	else
+		giveup_altivec(NULL):	/* just enable AltiVec for kernel - force */
+#else
+	giveup_altivec(last_task_used_altivec);
+#endif /* __SMP __ */
+	printk("MSR_VEC in enable_altivec_kernel\n");
+}
+#endif /* CONFIG_ALTIVEC */
+
 void
 enable_kernel_fp(void)
 {
@@ -162,6 +178,15 @@
 #endif /* __SMP__ */
 }
 
+int
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+{
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+	memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
+	return 1;
+}
+
 void
 _switch_to(struct task_struct *prev, struct task_struct *new,
 	  struct task_struct **last)
@@ -194,6 +219,7 @@
 	 */
 	if ( prev->thread.regs && (prev->thread.regs->msr & MSR_FP) )
 		giveup_fpu(prev);
+#ifdef CONFIG_ALTIVEC	
 	/*
 	 * If the previous thread 1) has some altivec regs it wants saved
 	 * (has bits in vrsave set) and 2) used altivec in the last quantum
@@ -206,6 +232,7 @@
 	if ( (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) &&
 	     prev->thread.vrsave )
 		giveup_altivec(prev);
+#endif /* CONFIG_ALTIVEC */	
 	prev->last_processor = prev->processor;
 	current_set[smp_processor_id()] = new;
 #endif /* __SMP__ */
@@ -337,13 +364,18 @@
 	p->thread.fpscr = current->thread.fpscr;
 	childregs->msr &= ~MSR_FP;
 
+#ifdef CONFIG_ALTIVEC
+	/*
+	 * copy altiVec info - assume lazy altiVec switch
+	 * - kumar
+	 */
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
-	if ( p->thread.vrsave )
-		memcpy(&p->thread.vrf, &current->thread.vrf, sizeof(p->thread.vrf));
+
+	memcpy(&p->thread.vr, &current->thread.vr, sizeof(p->thread.vr));
 	p->thread.vscr = current->thread.vscr;
-	p->thread.vrsave = current->thread.vrsave;
 	childregs->msr &= ~MSR_VEC;
+#endif /* CONFIG_ALTIVEC */
 
 #ifdef __SMP__
 	p->last_processor = NO_PROC_ID;
@@ -463,6 +495,10 @@
 		goto out;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+	if (regs->msr & MSR_VEC)
+		giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */ 
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
 	putname(filename);
 out:
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.44/linux/arch/ppc/kernel/prom.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/prom.c	Sun Feb 13 10:47:01 2000
@@ -802,42 +802,19 @@
 {
 	unsigned int len;
 	int width = 640, height = 480, depth = 8, pitch;
-	unsigned  address;
+	unsigned address;
 	boot_infos_t* bi;
 	unsigned long offset = reloc_offset();
 	
-	prom_print(RELOC("Initing fake screen\n"));
+	prom_print(RELOC("Initializing fake screen\n"));
 
-	len = 0;
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &width, sizeof(width));
+	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &height, sizeof(height));
 	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len));
-	if (len == 0)
-		prom_print(RELOC("Warning: assuming display depth = 8\n"));
-	else
-		depth = len;
-	width = len = 0;
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len));
-	width = len;
-	if (width == 0) {
-		prom_print(RELOC("Failed to get width\n"));
-		return;
-	}
-	height = len = 0;
-	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len));
-	height = len;
-	if (height == 0) {
-		prom_print(RELOC("Failed to get height\n"));
-		return;
-	}
-	pitch = len = 0;
+	pitch = width * ((depth + 7) / 8);
 	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len));
-	pitch = len;
-	if (pitch == 0) {
-		prom_print(RELOC("Failed to get pitch\n"));
-		return;
-	}
-	address = len = 0;
+	address = 0;
 	call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len));
-	address = len;
 	if (address == 0) {
 		prom_print(RELOC("Failed to get address\n"));
 		return;
@@ -846,22 +823,22 @@
 	/* kludge for valkyrie */
 	if (strcmp(dp->name, "valkyrie") == 0) 
 	    address += 0x1000;
-    }
 #endif
  
-    RELOC(disp_bi) = &fake_bi;
-    bi = PTRRELOC((&fake_bi));
-    RELOC(g_loc_X) = 0;
-    RELOC(g_loc_Y) = 0;
-    RELOC(g_max_loc_X) = width / 8;
-    RELOC(g_max_loc_Y) = height / 16;
-    bi->logicalDisplayBase = (unsigned char *)address;
-    bi->dispDeviceBase = (unsigned char *)address;
-    bi->dispDeviceRowBytes = pitch;
-    bi->dispDeviceDepth = depth;
-    bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
-    bi->dispDeviceRect[2] = width;
-    bi->dispDeviceRect[3] = height;
+	RELOC(disp_bi) = &fake_bi;
+	bi = PTRRELOC((&fake_bi));
+	RELOC(g_loc_X) = 0;
+	RELOC(g_loc_Y) = 0;
+	RELOC(g_max_loc_X) = width / 8;
+	RELOC(g_max_loc_Y) = height / 16;
+	bi->logicalDisplayBase = (unsigned char *)address;
+	bi->dispDeviceBase = (unsigned char *)address;
+	bi->dispDeviceRowBytes = pitch;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+	RELOC(disp_bi) = 0;
 }
 #endif
 
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.44/linux/arch/ppc/kernel/setup.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/setup.c	Sun Feb 13 10:47:01 2000
@@ -221,7 +221,7 @@
 		if ( i )
 			len += sprintf(len+buffer,"\n");
 		len += sprintf(len+buffer,"processor\t: %lu\n",i);
-		len += sprintf(len+buffer,"cpu\t\t:  ");
+		len += sprintf(len+buffer,"cpu\t\t: ");
 
 		pvr = GET_PVR;
 	
@@ -656,7 +656,6 @@
 
 #ifdef CONFIG_BOOTX_TEXT
 	map_bootx_text();
-	prom_print("identify machine\n");
 #endif
 
 #ifdef CONFIG_XMON
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.44/linux/arch/ppc/kernel/smp.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/ppc/kernel/smp.c	Sun Feb 13 10:47:01 2000
@@ -53,7 +53,6 @@
 cycles_t cacheflush_time;
 
 /* all cpu mappings are 1-1 -- Cort */
-int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
 volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 
 int start_secondary(void *);
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.3.44/linux/arch/ppc/kernel/syscalls.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/syscalls.c	Sun Feb 13 10:47:01 2000
@@ -252,14 +252,13 @@
 
 asmlinkage int sys_uname(struct old_utsname * name)
 {
-	int err;
-	
-	if (!name)
-		return -EFAULT;
+	int err = -EFAULT;
+
 	down_read(&uts_sem);
-	err = copy_to_user(name, &system_utsname, sizeof (*name));
-	up(&uts_sem);
-	return err ? -EFAULT : 0;
+	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+		err = 0;
+	up_read(&uts_sem);
+	return err;
 }
 
 asmlinkage int sys_olduname(struct oldold_utsname * name)
@@ -282,8 +281,8 @@
 	error -= __put_user(0,name->version+__OLD_UTS_LEN);
 	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	error = __put_user(0,name->machine+__OLD_UTS_LEN);
-	error = error ? -EFAULT : 0;
-	up(&uts_sem);
+	up_read(&uts_sem);
 
+	error = error ? -EFAULT : 0;
 	return error;
 }
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.3.44/linux/arch/ppc/kernel/traps.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/kernel/traps.c	Sun Feb 13 10:47:01 2000
@@ -118,11 +118,11 @@
 		default:
 			printk("Unknown values in msr\n");
 		}
+		show_regs(regs);
+		print_backtrace((unsigned long *)regs->gpr[1]);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		debugger(regs);
 #endif
-		show_regs(regs);
-		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("machine check");
 	}
 	_exception(SIGSEGV, regs);	
@@ -141,44 +141,6 @@
 	print_backtrace((unsigned long *)regs->gpr[1]);
 	panic("System Management Interrupt");
 }
-
-#if defined(CONFIG_ALTIVEC)
-void
-AltiVecUnavailable(struct pt_regs *regs)
-{
-	/*
-	 * This should be changed so we don't take a trap if coming
-	 * back when last_task_used_altivec == current.  We should also
-	 * allow the kernel to use the altivec regs on UP to store tasks
-	 * regs during switch
-	 *  -- Cort
-	 */
-	if ( regs->msr & MSR_VEC )
-	{
-		show_regs(regs);
-		panic("AltiVec trap with Altivec enabled!\n");
-	}
-		
-	if ( !user_mode(regs) )
-	{
-		show_regs(regs);
-		panic("Kernel Used Altivec with MSR_VEC off!\n");
-	}
-
-	if ( last_task_used_altivec != current )
-	{
-		if ( last_task_used_altivec )
-			giveup_altivec(current);
-		load_up_altivec(current);
-		/* on SMP we always save/restore on switch */
-#ifndef __SMP__		
-		last_task_used_altivec = current;
-#endif		
-	}
-	/* enable altivec for the task on return */
-	regs->msr |= MSR_VEC;
-}
-#endif /* CONFIG_ALTIVEC */
 
 void
 UnknownException(struct pt_regs *regs)
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S
--- v2.3.44/linux/arch/ppc/lib/string.S	Fri Oct 15 15:25:13 1999
+++ linux/arch/ppc/lib/string.S	Sun Feb 13 10:47:01 2000
@@ -12,6 +12,11 @@
 #include <asm/processor.h>
 #include <asm/errno.h>
 
+CACHELINE_BYTES = 32
+LG_CACHELINE_BYTES = 5
+CACHELINE_MASK = 0x1f
+CACHELINE_WORDS = 8
+
 	.globl	strcpy
 strcpy:
 	addi	r5,r3,-1
@@ -70,6 +75,55 @@
 	subf	r3,r3,r4
 	blr
 
+/*
+ * Use dcbz on the complete cache lines in the destination
+ * to set them to zero.  This requires that the destination
+ * area is cacheable.  -- paulus
+ */
+	.globl	cacheable_memzero
+cacheable_memzero:
+	mr	r5,r4
+	li	r4,0
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
+	add	r8,r7,r5
+	srwi	r9,r8,LG_CACHELINE_BYTES
+	addic.	r9,r9,-1	/* total number of complete cachelines */
+	ble	2f
+	xori	r0,r7,CACHELINE_MASK & ~3
+	srwi.	r0,r0,2
+	beq	3f
+	mtctr	r0
+4:	stwu	r4,4(r6)
+	bdnz	4b
+3:	mtctr	r9
+	li	r7,4
+10:	dcbz	r7,r6
+	addi	r6,r6,CACHELINE_BYTES
+	bdnz	10b
+	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
+	addi	r5,r5,4
+2:	srwi	r0,r5,2
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+
 	.globl	memset
 memset:
 	rlwimi	r4,r4,8,16,23
@@ -82,7 +136,7 @@
 	andi.	r0,r6,3
 	add	r5,r0,r5
 	subf	r6,r0,r6
-	rlwinm	r0,r5,32-2,2,31
+	srwi	r0,r5,2
 	mtctr	r0
 	bdz	6f
 1:	stwu	r4,4(r6)
@@ -103,6 +157,87 @@
 	mr	r4,r6
 	b	memcpy
 
+/*
+ * This version uses dcbz on the complete cache lines in the
+ * destination area to reduce memory traffic.  This requires that
+ * the destination area is cacheable.
+ * We only use this version if the source and dest don't overlap.
+ * -- paulus.
+ */
+	.global	cacheable_memcpy
+cacheable_memcpy:
+	add	r7,r3,r5		/* test if the src & dst overlap */
+	add	r8,r4,r5
+	cmplw	0,r4,r7
+	cmplw	1,r3,r8
+	crand	0,0,4			/* cr0.lt &= cr1.lt */
+	blt	memcpy			/* if regions overlap */
+
+	addi	r4,r4,-4
+	addi	r6,r3,-4
+	neg	r0,r3
+	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
+	beq	58f
+
+	cmplw	0,r5,r0			/* is this more than total to do? */
+	blt	63f			/* if not much to do */
+	andi.	r8,r0,3			/* get it word-aligned first */
+	subf	r5,r0,r5
+	mtctr	r8
+	beq+	61f
+70:	lbz	r9,4(r4)		/* do some bytes */
+	stb	r9,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	70b
+61:	srwi.	r0,r0,2
+	mtctr	r0
+	beq	58f
+72:	lwzu	r9,4(r4)		/* do some words */
+	stwu	r9,4(r6)
+	bdnz	72b
+
+58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
+	li	r11,4
+	mtctr	r0
+	beq	63f
+53:	dcbz	r11,r6
+	lwz	r7,4(r4)
+	lwz	r8,8(r4)
+	lwz	r9,12(r4)
+	lwzu	r10,16(r4)
+	stw	r7,4(r6)
+	stw	r8,8(r6)
+	stw	r9,12(r6)
+	stwu	r10,16(r6)
+	lwz	r7,4(r4)
+	lwz	r8,8(r4)
+	lwz	r9,12(r4)
+	lwzu	r10,16(r4)
+	stw	r7,4(r6)
+	stw	r8,8(r6)
+	stw	r9,12(r6)
+	stwu	r10,16(r6)
+	bdnz	53b
+
+63:	srwi.	r0,r5,2
+	mtctr	r0
+	beq	64f
+30:	lwzu	r0,4(r4)
+	stwu	r0,4(r6)
+	bdnz	30b
+
+64:	andi.	r0,r5,3
+	mtctr	r0
+	beq+	65f
+40:	lbz	r0,4(r4)
+	stb	r0,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	40b
+65:	blr
+
 	.globl	memmove
 memmove:
 	cmplw	0,r3,r4
@@ -111,7 +246,7 @@
 
 	.globl	memcpy
 memcpy:
-	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	srwi.	r7,r5,3
 	addi	r6,r3,-4
 	addi	r4,r4,-4
 	beq	2f			/* if less than 8 bytes to do */
@@ -218,106 +353,167 @@
 
 	.globl	__copy_tofrom_user
 __copy_tofrom_user:
-	srwi.	r7,r5,3
-	addi	r6,r3,-4
 	addi	r4,r4,-4
-	li	r3,0		/* success return value */
-	beq	2f		/* if less than 8 bytes to do */
-	andi.	r0,r6,3		/* get dest word aligned */
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,4(r4)
-11:	lwzu	r8,8(r4)
-12:	stw	r7,4(r6)
-13:	stwu	r8,8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-14:	lwzu	r0,4(r4)
-	addi	r5,r5,-4
-15:	stwu	r0,4(r6)
-3:	cmpwi	0,r5,0		/* do 1 byte at a time for the remainder */
-	beqlr
-	mtctr	r5
-	addi	r4,r4,3
-	addi	r6,r6,3
-4:	lbzu	r0,1(r4)
-16:	stbu	r0,1(r6)
-	bdnz	4b
-	blr
-5:	subfic	r0,r0,4		/* copy bytes until we have the */
-	mtctr	r0		/* destination 4-byte aligned */
-	subf	r5,r0,r5
-6:	lbz	r7,4(r4)
+	addi	r6,r3,-4
+	neg	r0,r3
+	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
+	beq	58f
+
+	cmplw	0,r5,r0			/* is this more than total to do? */
+	blt	63f			/* if not much to do */
+	andi.	r8,r0,3			/* get it word-aligned first */
+	mtctr	r8
+	beq+	61f
+70:	lbz	r9,4(r4)		/* do some bytes */
+71:	stb	r9,4(r6)
 	addi	r4,r4,1
-17:	stb	r7,4(r6)
 	addi	r6,r6,1
-	bdnz	6b
-	srwi.	r7,r5,3
-	beq	2b
-	mtctr	r7
-	b	1b
-/* we come here on a fault in the 8-byte-at-a-time loop */
-88:	subi	r4,r4,8		/* compensate for the lwzu */
-98:	mfctr	r0
-	rlwimi	r5,r0,3,0,28	/* use the byte-at-a-time loop to */
-	b	3b		/* copy up to the byte at fault */
-/* here on a write fault in the single-word copy */
-96:	subi	r4,r4,4
-	b	3b
-/* here on a read fault in the initial single-byte copy */
-90:	mfctr	r3
-	add	r3,r3,r5
-	b	70f
-/* here on a read fault in the final single-byte copy */
-99:	mfctr	r3
-	subi	r6,r6,3
-/* clear out the rest of the destination: r3 bytes starting at 4(r6) */
-70:	li	r0,0
-	mr.	r5,r3
-	beq	76f
-71:	andi.	r4,r6,3
-	beq	72f
-77:	stb	r0,4(r6)
+	bdnz	70b
+61:	subf	r5,r0,r5
+	srwi.	r0,r0,2
+	mtctr	r0
+	beq	58f
+72:	lwzu	r9,4(r4)		/* do some words */
+73:	stwu	r9,4(r6)
+	bdnz	72b
+
+58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
+	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
+	li	r11,4
+	mtctr	r0
+	beq	63f
+53:	dcbz	r11,r6
+10:	lwz	r7,4(r4)
+11:	lwz	r8,8(r4)
+12:	lwz	r9,12(r4)
+13:	lwzu	r10,16(r4)
+14:	stw	r7,4(r6)
+15:	stw	r8,8(r6)
+16:	stw	r9,12(r6)
+17:	stwu	r10,16(r6)
+20:	lwz	r7,4(r4)
+21:	lwz	r8,8(r4)
+22:	lwz	r9,12(r4)
+23:	lwzu	r10,16(r4)
+24:	stw	r7,4(r6)
+25:	stw	r8,8(r6)
+26:	stw	r9,12(r6)
+27:	stwu	r10,16(r6)
+	bdnz	53b
+
+63:	srwi.	r0,r5,2
+	mtctr	r0
+	beq	64f
+30:	lwzu	r0,4(r4)
+31:	stwu	r0,4(r6)
+	bdnz	30b
+
+64:	andi.	r0,r5,3
+	mtctr	r0
+	beq+	65f
+40:	lbz	r0,4(r4)
+41:	stb	r0,4(r6)
+	addi	r4,r4,1
 	addi	r6,r6,1
-	addic.	r5,r5,-1
-	bne	71b
-72:	srwi.	r7,r5,2
-	beq	73f
-	mtctr	r7
-74:	stwu	r0,4(r6)
-	bdnz	74b
-73:	andi.	r5,r5,3
-	beq	76f
-	mtctr	r5
-	addi	r6,r6,3
-75:	stbu	r0,1(r6)
-	bdnz	75b
-76:	blr
-/* here on a write fault in the initial single-byte copy */
-80:	mfctr	r3
-	add	r3,r3,r5
-	blr
-/* here on a write fault in the final single-byte copy */
-81:	mfctr	r3
+	bdnz	40b
+65:	li	r3,0
 	blr
 
+/* read fault, initial single-byte copy */
+100:	li	r4,0
+	b	90f
+/* write fault, initial single-byte copy */
+101:	li	r4,1
+90:	subf	r5,r8,r5
+	li	r3,0
+	b	99f
+/* read fault, initial word copy */
+102:	li	r4,0
+	b	91f
+/* write fault, initial word copy */
+103:	li	r4,1
+91:	li	r3,2
+	b	99f
+/* read fault in 2nd half of cacheline loop */
+106:	addi	r5,r5,-16
+/* read fault in 1st half of cacheline loop */
+104:	li	r4,0
+	b	92f
+/* write fault in 2nd half of cacheline loop */
+107:	addi	r5,r5,-16
+/* fault on dcbz (effectively a write fault) */
+/* or write fault in 1st half of cacheline loop */
+105:	li	r4,1
+92:	li	r3,LG_CACHELINE_BYTES
+	b	99f
+/* read fault in final word loop */
+108:	li	r4,0
+	b	93f
+/* write fault in final word loop */
+109:	li	r4,1
+93:	andi.	r5,r5,3
+	li	r3,2
+	b	99f
+/* read fault in final byte loop */
+110:	li	r4,0
+	b	94f
+/* write fault in final byte loop */
+111:	li	r4,1
+94:	li	r5,0
+	li	r3,0
+/*
+ * At this stage the number of bytes not copied is
+ * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ */
+99:	mfctr	r0
+	slw	r3,r0,r3
+	add	r3,r3,r5
+	cmpwi	0,r4,0
+	bne	120f
+/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+	srwi.	r0,r3,2
+	li	r9,0
+	mtctr	r0
+	beq	113f
+112:	stwu	r9,4(r6)
+	bdnz	112b
+113:	andi.	r0,r3,3
+	mtctr	r0
+	beq	120f
+114:	stb	r9,4(r6)
+	addi	r6,r6,1
+	bdnz	114b
+120:	blr
+
 .section __ex_table,"a"
 	.align	2
-	.long	1b,98b
-	.long	11b,98b
-	.long	12b,88b
-	.long	13b,88b
-	.long	14b,3b
-	.long	15b,96b
-	.long	4b,99b
-	.long	16b,81b
-	.long	6b,90b
-	.long	17b,80b
-	.long	77b,76b
-	.long	74b,76b
-	.long	75b,76b
+	.long	70b,100b
+	.long	71b,101b
+	.long	72b,102b
+	.long	73b,103b
+	.long	53b,105b
+	.long	10b,104b
+	.long	11b,104b
+	.long	12b,104b
+	.long	13b,104b
+	.long	14b,105b
+	.long	15b,105b
+	.long	16b,105b
+	.long	17b,105b
+	.long	20b,106b
+	.long	21b,106b
+	.long	22b,106b
+	.long	23b,106b
+	.long	24b,107b
+	.long	25b,107b
+	.long	26b,107b
+	.long	27b,107b
+	.long	30b,108b
+	.long	31b,109b
+	.long	40b,110b
+	.long	41b,111b
+	.long	112b,120b
+	.long	114b,120b
 .text
 
 	.globl	__clear_user
@@ -334,7 +530,6 @@
 	andi.	r0,r6,3
 	add	r4,r0,r4
 	subf	r6,r0,r6
-	/*rlwinm	r0,r4,32-2,2,31*/
 	srwi	r0,r4,2
 	mtctr	r0
 	bdz	6f
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.44/linux/arch/ppc/mm/init.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/mm/init.c	Sun Feb 13 10:47:01 2000
@@ -1107,7 +1107,7 @@
  */
 void __init paging_init(void)
 {
-	unsigned int zones_size[MAX_NR_ZONES], i;
+	unsigned long zones_size[MAX_NR_ZONES], i;
 
 	/*
 	 * Grab some memory for bad_page and bad_pagetable to use.
@@ -1197,7 +1197,7 @@
 	unsigned long a, total;
 	
 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (64<<20)
+#define RAM_LIMIT (768<<20)
 
 	memory_node = find_devices("memory");
 	if (memory_node == NULL) {
diff -u --recursive --new-file v2.3.44/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.3.44/linux/arch/ppc/xmon/start.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/ppc/xmon/start.c	Sun Feb 13 10:47:01 2000
@@ -115,42 +115,41 @@
 int
 xmon_write(void *handle, void *ptr, int nb)
 {
-    char *p = ptr;
-    int i, c, ct;
+	char *p = ptr;
+	int i, c, ct;
 
 #ifdef CONFIG_BOOTX_TEXT
-    if (use_screen) {
-	/* write it on the screen */
-	for (i = 0; i < nb; ++i)
-	    drawchar(*p++);
-	return nb;
-    }
+	if (use_screen) {
+		/* write it on the screen */
+		for (i = 0; i < nb; ++i)
+			drawchar(*p++);
+		return nb;
+	}
 #endif
-    if (!scc_initialized)
-	xmon_init_scc();
-    for (i = 0; i < nb; ++i) {
-    ct = 0;
-	while ((*sccc & TXRDY) == 0)
+	if (!scc_initialized)
+		xmon_init_scc();
+	ct = 0;
+	for (i = 0; i < nb; ++i) {
+		while ((*sccc & TXRDY) == 0) {
 #ifdef CONFIG_ADB	    
-	    if (sys_ctrler == SYS_CTRLER_PMU)
-		pmu_poll();
-#else
-		;
+			if (sys_ctrler == SYS_CTRLER_PMU)
+				pmu_poll();
 #endif /* CONFIG_ADB */
-	c = p[i];
-	if (c == '\n' && !ct) {
-	    c = '\r';
-		ct = 1;
-	    --i;
-	} else {
-	    if (console)
-		printk("%c", c);
-	    ct = 0;
+		}
+		c = p[i];
+		if (c == '\n' && !ct) {
+			c = '\r';
+			ct = 1;
+			--i;
+		} else {
+			if (console)
+				printk("%c", c);
+			ct = 0;
+		}
+		buf_access();
+		*sccd = c;
 	}
-	buf_access();
-	*sccd = c;
-    }
-    return i;
+	return i;
 }
 
 int xmon_wants_key;
@@ -285,7 +284,7 @@
 	{
 		int i, x;
 
-		if (macio_node != 0) {
+		if (via_modem && macio_node != 0) {
 			unsigned int t0;
 
 			feature_set(macio_node, FEATURE_Modem_power);
diff -u --recursive --new-file v2.3.44/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v2.3.44/linux/arch/sparc/kernel/ioport.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc/kernel/ioport.c	Sun Feb 13 10:18:03 2000
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.31 2000/02/06 22:55:32 zaitcev Exp $
+/* $Id: ioport.c,v 1.32 2000/02/12 03:04:48 zaitcev Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -562,7 +562,7 @@
 	{
 		int x;
 		for (x = 0; x < n; x += PAGE_SIZE) {
-			(*_sparc_unmapioaddr)(p + n);
+			(*_sparc_unmapioaddr)((unsigned long)p + n);
 		}
 	}
 
diff -u --recursive --new-file v2.3.44/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- v2.3.44/linux/arch/sparc/kernel/pcic.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/pcic.c	Sun Feb 13 10:18:03 2000
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.12 2000/01/22 07:35:25 zaitcev Exp $
+/* $Id: pcic.c,v 1.13 2000/02/12 03:05:37 zaitcev Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -784,6 +784,7 @@
 
 static __inline__ unsigned long do_gettimeoffset(void)
 {
+	struct tasklet_struct *t;
 	unsigned long offset = 0;
 
 	/* 
@@ -794,7 +795,8 @@
 	    readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
 	count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
 
-	if(test_bit(TIMER_BH, &bh_active))
+	t = &bh_task_vec[TIMER_BH];
+	if (test_bit(TASKLET_STATE_SCHED, &t->state))
 		offset = 1000000;
 	return offset + count;
 }
diff -u --recursive --new-file v2.3.44/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.44/linux/arch/sparc/mm/srmmu.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc/mm/srmmu.c	Sun Feb 13 18:20:21 2000
@@ -1366,7 +1366,7 @@
 	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
 		struct vm_area_struct *vmaring;
 		struct file *file;
-		struct inode *inode;
+		struct address_space *mapping;
 		unsigned long flags, offset, vaddr, start;
 		int alias_found = 0;
 		pgd_t *pgdp;
@@ -1378,10 +1378,10 @@
 		file = vma->vm_file;
 		if (!file)
 			goto done;
-		inode = file->f_dentry->d_inode;
+		mapping = file->f_dentry->d_inode->i_mapping;
 		offset = (address & PAGE_MASK) - vma->vm_start;
-		spin_lock(&inode->i_shared_lock);
-		vmaring = inode->i_mmap; 
+		spin_lock(&mapping->i_shared_lock);
+		vmaring = mapping->i_mmap; 
 		do {
 			/* Do not mistake ourselves as another mapping. */
 			if(vmaring == vma)
@@ -1414,7 +1414,7 @@
 				}
 			}
 		} while ((vmaring = vmaring->vm_next_share) != NULL);
-		spin_unlock(&inode->i_shared_lock);
+		spin_unlock(&mapping->i_shared_lock);
 
 		if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
 			pgdp = srmmu_pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.3.44/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.44/linux/arch/sparc/mm/sun4c.c	Thu Feb 10 17:11:05 2000
+++ linux/arch/sparc/mm/sun4c.c	Sun Feb 13 18:20:21 2000
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.187 2000/02/08 07:46:01 davem Exp $
+/* $Id: sun4c.c,v 1.188 2000/02/12 03:07:35 zaitcev Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -591,7 +591,7 @@
 	return (pte << PAGE_SHIFT) + PAGE_OFFSET;
 }
 
-static unsigned long sun4c_unmap_dma_area(unsigned long busa, int len)
+static void sun4c_unmap_dma_area(unsigned long busa, int len)
 {
 	/* Fortunately for us, bus_addr == uncached_virt in sun4c. */
 	/* XXX Implement this */
@@ -2418,11 +2418,12 @@
 	if(dentry)
 		inode = dentry->d_inode;
 	if(inode) {
+		struct address_space *mapping = inode->i_mapping;
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
 		struct vm_area_struct *vmaring;
 		int alias_found = 0;
-		spin_lock(&inode->i_shared_lock);
-		vmaring = inode->i_mmap; 
+		spin_lock(&mapping->i_shared_lock);
+		vmaring = mapping->i_mmap; 
 		do {
 			unsigned long vaddr = vmaring->vm_start + offset;
 			unsigned long start;
@@ -2453,7 +2454,7 @@
 				}
 			}
 		} while ((vmaring = vmaring->vm_next_share) != NULL);
-		spin_unlock(&inode->i_shared_lock);
+		spin_unlock(&mapping->i_shared_lock);
 
 		if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = sun4c_pgd_offset(vma->vm_mm, address);
diff -u --recursive --new-file v2.3.44/linux/arch/sparc/mm/swift.S linux/arch/sparc/mm/swift.S
--- v2.3.44/linux/arch/sparc/mm/swift.S	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/mm/swift.S	Sun Feb 13 10:18:03 2000
@@ -1,4 +1,4 @@
-/* $Id: swift.S,v 1.3 1999/11/14 06:13:56 zaitcev Exp $
+/* $Id: swift.S,v 1.4 2000/02/12 03:08:47 zaitcev Exp $
  * swift.S: MicroSparc-II mmu/cache operations.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -41,10 +41,10 @@
 swift_flush_page_to_ram:
 	sethi	%hi(0x2000), %o0
 1:	subcc	%o0, 0x10, %o0
-	sta	%g0, [%o0] ASI_M_TXTC_TAG
+	add	%o0, %o0, %o1
 	sta	%g0, [%o0] ASI_M_DATAC_TAG
 	bne	1b
-	 nop
+	 sta	%g0, [%o1] ASI_M_TXTC_TAG
 	retl
 	 nop
 #else
diff -u --recursive --new-file v2.3.44/linux/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c
--- v2.3.44/linux/drivers/acorn/char/keyb_ps2.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/acorn/char/keyb_ps2.c	Sun Feb 13 10:45:13 2000
@@ -28,6 +28,7 @@
 #include <asm/iomd.h>
 #include <asm/system.h>
 
+extern struct tasklet_struct keyboard_tasklet;
 extern void kbd_reset_kdown(void);
 int kbd_read_mask;
 
@@ -318,7 +319,7 @@
 
 	while (inb(IOMD_KCTRL) & (1 << 5))
 		handle_rawcode(inb(IOMD_KARTRX));
-	mark_bh(KEYBOARD_BH);
+	tasklet_schedule(&keyboard_tasklet);
 }
 
 static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.3.44/linux/drivers/block/cs5530.c linux/drivers/block/cs5530.c
--- v2.3.44/linux/drivers/block/cs5530.c	Thu Feb 10 17:11:06 2000
+++ linux/drivers/block/cs5530.c	Sun Feb 13 18:21:45 2000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/cs5530.c		Version 0.2	Jan 30, 2000
+ * linux/drivers/block/cs5530.c		Version 0.5	Feb 13, 2000
  *
  * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
  * May be copied or modified under the terms of the GNU General Public License
@@ -285,8 +285,6 @@
 	}
 	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
 
-	if (!strcmp(drive->name, "hdc"))	/* FIXME */
-		return 0;
 	/*
 	 * Finally, turn DMA on in software, and exit.
 	 */
diff -u --recursive --new-file v2.3.44/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.44/linux/drivers/block/loop.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/block/loop.c	Sun Feb 13 10:33:23 2000
@@ -40,10 +40,10 @@
  *   it passes the underlying device's block number instead of the
  *   offset. This makes it change for a given block when the file is 
  *   moved/restored/copied and also doesn't work over NFS. 
- * AV, Feb 11, 2000: for files we pass the page index now. It should fix the
- *   problem above. Since the granularity is PAGE_CACHE_SIZE now it seems to
- *   be correct way. OTOH, taking the thing from x86 to Alpha may become
- *   interesting, so we might want to rethink it.
+ * AV, Feb 12, 2000: we pass the logical block number now. It fixes the
+ *   problem above. Encryption modules that used to rely on the old scheme
+ *   should just call ->i_mapping->bmap() to calculate the physical block
+ *   number.
  */ 
 
 #include <linux/module.h>
@@ -164,7 +164,8 @@
 	loop_sizes[lo->lo_number] = size;
 }
 
-static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos)
+static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
+	int blksize)
 {
 	struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
 	struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping;
@@ -177,6 +178,7 @@
 	index = pos >> PAGE_CACHE_SHIFT;
 	offset = pos & (PAGE_CACHE_SIZE - 1);
 	while (len > 0) {
+		int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize;
 		size = PAGE_CACHE_SIZE - offset;
 		if (size > len)
 			size = len;
@@ -187,7 +189,7 @@
 		if (aops->prepare_write(page, offset, offset+size))
 			goto unlock;
 		kaddr = (char*)page_address(page);
-		if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, index))
+		if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
 			goto write_fail;
 		if (aops->commit_write(file, page, offset, offset+size))
 			goto unlock;
@@ -217,6 +219,7 @@
 struct lo_read_data {
 	struct loop_device *lo;
 	char *data;
+	int blksize;
 };
 
 static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
@@ -225,12 +228,13 @@
 	unsigned long count = desc->count;
 	struct lo_read_data *p = (struct lo_read_data*)desc->buf;
 	struct loop_device *lo = p->lo;
+	int IV = page->index * (PAGE_CACHE_SIZE/p->blksize) + offset/p->blksize;
 
 	if (size > count)
 		size = count;
 
 	kaddr = (char*)kmap(page);
-	if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,page->index)) {
+	if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
 		size = 0;
 		printk(KERN_ERR "loop: transfer error block %ld\n",page->index);
 		desc->error = -EINVAL;
@@ -243,7 +247,8 @@
 	return size;
 }
 
-static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos)
+static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos,
+	int blksize)
 {
 	struct file *file = lo->lo_backing_file;
 	struct lo_read_data cookie;
@@ -251,6 +256,7 @@
 
 	cookie.lo = lo;
 	cookie.data = data;
+	cookie.blksize = blksize;
 	desc.written = 0;
 	desc.count = len;
 	desc.buf = (char*)&cookie;
@@ -287,8 +293,6 @@
 
 	dest_addr = current_request->buffer;
 	len = current_request->current_nr_sectors << 9;
-	if (lo->lo_flags & LO_FLAGS_DO_BMAP)
-		goto file_backed;
 
 	blksize = BLOCK_SIZE;
 	if (blksize_size[MAJOR(lo->lo_device)]) {
@@ -296,6 +300,10 @@
 	    if (!blksize)
 	      blksize = BLOCK_SIZE;
 	}
+
+	if (lo->lo_flags & LO_FLAGS_DO_BMAP)
+		goto file_backed;
+
 	if (blksize < 512) {
 		block = current_request->sector * (512/blksize);
 		offset = 0;
@@ -357,10 +365,10 @@
 	pos = ((loff_t)current_request->sector << 9) + lo->lo_offset;
 	spin_unlock_irq(&io_request_lock);
 	if (current_request->cmd == WRITE) {
-		if (lo_send(lo, dest_addr, len, pos))
+		if (lo_send(lo, dest_addr, len, pos, blksize))
 			goto error_out_lock;
 	} else {
-		if (lo_receive(lo, dest_addr, len, pos))
+		if (lo_receive(lo, dest_addr, len, pos, blksize))
 			goto error_out_lock;
 	}
 done:
@@ -416,6 +424,7 @@
 		   a file structure */
 		lo->lo_backing_file = NULL;
 	} else if (S_ISREG(inode->i_mode)) {
+		struct address_space_operations *aops;
 		/* Backed by a regular file - we need to hold onto a file
 		   structure for this file.  Friggin' NFS can't live without
 		   it on write and for reading we use do_generic_file_read(),
@@ -444,16 +453,23 @@
 				lo->lo_backing_file = NULL;
 			}
 		}
+		aops = lo->lo_dentry->d_inode->i_mapping->a_ops;
+		/*
+		 * If we can't read - sorry. If we only can't write - well,
+		 * it's going to be read-only.
+		 */
+		if (!aops->readpage)
+			error = -EINVAL;
+		else if (!aops->prepare_write || !aops->commit_write)
+			lo->lo_flags |= LO_FLAGS_READ_ONLY;
 	}
 	if (error)
 		goto out_putf;
 
-	if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) {
+	if (IS_RDONLY (inode) || is_read_only(lo->lo_device))
 		lo->lo_flags |= LO_FLAGS_READ_ONLY;
-		set_device_ro(dev, 1);
-	} else {
-		set_device_ro(dev, 0);
-	}
+
+	set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0);
 
 	lo->lo_dentry = dget(file->f_dentry);
 	lo->transfer = NULL;
diff -u --recursive --new-file v2.3.44/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.44/linux/drivers/char/Makefile	Thu Feb 10 17:11:07 2000
+++ linux/drivers/char/Makefile	Sun Feb 13 11:21:42 2000
@@ -45,8 +45,12 @@
 SERIAL   =serial.o
 
 ifeq ($(ARCH),m68k)
-  KEYBD    =
-  SERIAL   =
+   ifdef CONFIG_AMIGA
+      KEYBD = amikeyb.o
+   else
+      KEYBD    =
+   endif
+   SERIAL   =
 endif
 
 ifeq ($(ARCH),arm)
@@ -60,6 +64,7 @@
   SERIAL   =
 endif
 
+
 obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
 obj-$(CONFIG_SERIAL) += $(SERIAL)
 obj-$(CONFIG_SERIAL_21285) += serial_21285.o
@@ -96,6 +101,7 @@
 obj-$(CONFIG_SYNCLINK) += synclink.o
 obj-$(CONFIG_N_HDLC) += n_hdlc.o
 obj-$(CONFIG_SPECIALIX) += specialix.o
+obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 
 ifeq ($(CONFIG_SX),y)
 obj-y += sx.o generic_serial.o
diff -u --recursive --new-file v2.3.44/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c
--- v2.3.44/linux/drivers/char/amikeyb.c	Mon Aug  9 12:32:28 1999
+++ linux/drivers/char/amikeyb.c	Sun Feb 13 11:21:42 2000
@@ -17,13 +17,14 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/keyboard.h>
+#include <linux/kd.h>
+#include <linux/kbd_ll.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
-#include <linux/kd.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/kbd_ll.h>
+#include <linux/kbd_kern.h>
 
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
@@ -230,7 +231,7 @@
     /* switch CIA serial port to input mode */
     ciaa.cra &= ~0x40;
 
-    mark_bh(KEYBOARD_BH);
+    tasklet_schedule(&keyboard_tasklet);
 
     /* rotate scan code to get up/down bit in proper position */
     scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
diff -u --recursive --new-file v2.3.44/linux/drivers/char/amiserial.c linux/drivers/char/amiserial.c
--- v2.3.44/linux/drivers/char/amiserial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/amiserial.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,2264 @@
+/*
+ *  linux/drivers/char/amiserial.c
+ *
+ * Serial driver for the amiga builtin port.
+ *
+ * This code was created by taking serial.c version 4.30 from kernel
+ * release 2.3.22, replacing all hardware related stuff with the
+ * corresponding amiga hardware actions, and removing all irrelevant
+ * code. As a consequence, it uses many of the constants and names
+ * associated with the registers and bits of 16550 compatible UARTS -
+ * but only to keep track of status, etc in the state variables. It
+ * was done this was to make it easier to keep the code in line with
+ * (non hardware specific) changes to serial.c.
+ *
+ * The port is registered with the tty driver as minor device 64, and
+ * therefore other ports should should only use 65 upwards.
+ *
+ * Richard Lucock 28/12/99
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
+ * 		1998, 1999  Theodore Ts'o
+ *
+ */
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ *
+ * SERIAL_PARANOIA_CHECK
+ * 		Check the magic number for the async_structure where
+ * 		ever possible.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+/* Sanity checks */
+
+#define SERIAL_INLINE
+  
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+/*
+ * End of serial driver configuration section.
+ */
+
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+static char *serial_version = "4.30";
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+	
+static char *serial_name = "Amiga-builtin serial driver";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+static struct async_struct *IRQ_ports;
+
+static unsigned char current_ctl_bits;
+
+static void change_speed(struct async_struct *info, struct termios *old);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+
+static struct serial_state rs_table[1];
+
+#define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
+
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
+
+#include <asm/uaccess.h>
+
+#define serial_isroot()	(capable(CAP_SYS_ADMIN))
+
+
+static inline int serial_paranoia_check(struct async_struct *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/* some serial hardware definitions */
+#define SDR_OVRUN   (1<<15)
+#define SDR_RBF     (1<<14)
+#define SDR_TBE     (1<<13)
+#define SDR_TSRE    (1<<12)
+
+#define SERPER_PARENB    (1<<15)
+
+#define AC_SETCLR   (1<<15)
+#define AC_UARTBRK  (1<<11)
+
+#define SER_DTR     (1<<7)
+#define SER_RTS     (1<<6)
+#define SER_DCD     (1<<5)
+#define SER_CTS     (1<<4)
+#define SER_DSR     (1<<3)
+
+static __inline__ void rtsdtr_ctrl(int bits)
+{
+    ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->IER & UART_IER_THRI) {
+		info->IER &= ~UART_IER_THRI;
+		/* disable Tx interrupt and remove any pending interrupts */
+		custom.intena = IF_TBE;
+		mb();
+		custom.intreq = IF_TBE;
+		mb();
+	}
+	restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		custom.intena = IF_SETCLR | IF_TBE;
+		mb();
+		/* set a pending Tx Interrupt, transmitter should restart now */
+		custom.intreq = IF_SETCLR | IF_TBE;
+		mb();
+	}
+	restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * 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 async_struct *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct async_struct *info)
+{
+        int status;
+	int serdatr;
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	struct	async_icount *icount;
+
+	icount = &info->state->icount;
+
+	status = UART_LSR_DR; /* We obviously have a character! */
+	serdatr = custom.serdatr;
+	mb();
+	custom.intreq = IF_RBF;
+	mb();
+
+	if((serdatr & 0x1ff) == 0)
+	    status |= UART_LSR_BI;
+	if(serdatr & SDR_OVRUN)
+	    status |= UART_LSR_OE;
+		  
+	ch = serdatr & 0xff;
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+	  goto ignore_char;
+	*tty->flip.char_buf_ptr = ch;
+	icount->rx++;
+		
+#ifdef SERIAL_DEBUG_INTR
+	printk("DR%02x:%02x...", ch, status);
+#endif
+	*tty->flip.flag_buf_ptr = 0;
+
+	/*
+	 * We don't handle parity or frame errors - but I have left
+	 * the code in, since I'm not sure that the errors can't be
+	 * detected.
+	 */
+
+	if (status & (UART_LSR_BI | UART_LSR_PE |
+		      UART_LSR_FE | UART_LSR_OE)) {
+	  /*
+	   * For statistics only
+	   */
+	  if (status & UART_LSR_BI) {
+	    status &= ~(UART_LSR_FE | UART_LSR_PE);
+	    icount->brk++;
+	  } else if (status & UART_LSR_PE)
+	    icount->parity++;
+	  else if (status & UART_LSR_FE)
+	    icount->frame++;
+	  if (status & UART_LSR_OE)
+	    icount->overrun++;
+
+	  /*
+	   * Now check to see if character should be
+	   * ignored, and mask off conditions which
+	   * should be ignored.
+	   */
+	  if (status & info->ignore_status_mask)
+	    goto ignore_char;
+
+	  status &= info->read_status_mask;
+
+	  if (status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+	    printk("handling break....");
+#endif
+	    *tty->flip.flag_buf_ptr = TTY_BREAK;
+	    if (info->flags & ASYNC_SAK)
+	      do_SAK(tty);
+	  } else if (status & UART_LSR_PE)
+	    *tty->flip.flag_buf_ptr = TTY_PARITY;
+	  else if (status & UART_LSR_FE)
+	    *tty->flip.flag_buf_ptr = TTY_FRAME;
+	  if (status & UART_LSR_OE) {
+	    /*
+	     * Overrun is special, since it's
+	     * reported immediately, and doesn't
+	     * affect the current character
+	     */
+	    if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+	      tty->flip.count++;
+	      tty->flip.flag_buf_ptr++;
+	      tty->flip.char_buf_ptr++;
+	      *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+	    }
+	  }
+	}
+	tty->flip.flag_buf_ptr++;
+	tty->flip.char_buf_ptr++;
+	tty->flip.count++;
+ ignore_char:
+
+	tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct async_struct *info)
+{
+	custom.intreq = IF_TBE;
+	mb();
+	if (info->x_char) {
+	        custom.serdat = info->x_char | 0x100;
+		mb();
+		info->state->icount.tx++;
+		info->x_char = 0;
+		return;
+	}
+	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+	    info->tty->hw_stopped) {
+		info->IER &= ~UART_IER_THRI;
+	        custom.intena = IF_TBE;
+		mb();
+		return;
+	}
+	
+	custom.serdat = info->xmit_buf[info->xmit_tail++] | 0x100;
+	mb();
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->state->icount.tx++;
+	--info->xmit_cnt;
+	
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+	if (info->xmit_cnt <= 0) {
+	        custom.intena = IF_TBE;
+		mb();
+		info->IER &= ~UART_IER_THRI;
+	}
+}
+
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+	unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
+	unsigned char dstatus;
+	struct	async_icount *icount;
+
+	/* Determine bits that have changed */
+	dstatus = status ^ current_ctl_bits;
+	current_ctl_bits = status;
+
+	if (dstatus) {
+		icount = &info->state->icount;
+		/* update input line counters */
+		if (dstatus & SER_DSR)
+			icount->dsr++;
+		if (dstatus & SER_DCD) {
+			icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+			if ((info->flags & ASYNC_HARDPPS_CD) &&
+			    !(status & SER_DCD))
+				hardpps();
+#endif
+		}
+		if (dstatus & SER_CTS)
+			icount->cts++;
+		wake_up_interruptible(&info->delta_msr_wait);
+	}
+
+	if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+		printk("ttyS%02d CD now %s...", info->line,
+		       (!(status & SER_DCD)) ? "on" : "off");
+#endif		
+		if (!(status & SER_DCD))
+			wake_up_interruptible(&info->open_wait);
+		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+			printk("doing serial hangup...");
+#endif
+			if (info->tty)
+				tty_hangup(info->tty);
+		}
+	}
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (!(status & SER_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx start...");
+#endif
+				info->tty->hw_stopped = 0;
+				info->IER |= UART_IER_THRI;
+				custom.intena = IF_SETCLR | IF_TBE;
+				mb();
+				/* set a pending Tx Interrupt, transmitter should restart now */
+				custom.intreq = IF_SETCLR | IF_TBE;
+				mb();
+				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+				return;
+			}
+		} else {
+			if ((status & SER_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx stop...");
+#endif
+				info->tty->hw_stopped = 1;
+				info->IER &= ~UART_IER_THRI;
+				/* disable Tx interrupt and remove any pending interrupts */
+				custom.intena = IF_TBE;
+				mb();
+				custom.intreq = IF_TBE;
+				mb();
+			}
+		}
+	}
+}
+
+static void ser_vbl_int( int irq, void *data, struct pt_regs *regs)
+{
+        /* vbl is just a periodic interrupt we tie into to update modem status */
+	struct async_struct * info = IRQ_ports;
+	/*
+	 * TBD - is it better to unregister from this interrupt or to
+	 * ignore it if MSI is clear ?
+	 */
+	if(info->IER & UART_IER_MSI)
+	  check_modem_status(info);
+}
+
+static void ser_rx_int(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct async_struct * info;
+	
+#ifdef SERIAL_DEBUG_INTR
+	printk("ser_rx_int...");
+#endif
+	
+	info = IRQ_ports;
+	if (!info || !info->tty)
+		return;
+
+	receive_chars(info);
+	info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+
+static void ser_tx_int(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct async_struct * info;
+	
+	if (custom.serdatr & SDR_TBE) {
+#ifdef SERIAL_DEBUG_INTR
+	  printk("ser_tx_int...");
+#endif
+	
+	  info = IRQ_ports;
+	  if (!info || !info->tty)
+	    return;
+
+	  transmit_chars(info);
+	  info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+	  printk("end.\n");
+#endif
+	}
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct async_struct	*info = (struct async_struct *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+static int startup(struct async_struct * info)
+{
+	unsigned long flags;
+	int	retval=0;
+	unsigned long page;
+
+	page = get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	save_flags(flags); cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		free_page(page);
+		goto errout;
+	}
+
+	if (info->xmit_buf)
+		free_page(page);
+	else
+		info->xmit_buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttys%d ...", info->line);
+#endif
+
+	/* Clear anything in the input buffer */
+
+	custom.intreq = IF_RBF;
+	mb();
+
+	retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);
+	if (retval) {
+	  if (serial_isroot()) {
+	    if (info->tty)
+	      set_bit(TTY_IO_ERROR,
+		      &info->tty->flags);
+	    retval = 0;
+	  }
+	  goto errout;
+	}
+
+	/* enable both Rx and Tx interrupts */
+	custom.intena = IF_SETCLR | IF_RBF | IF_TBE;
+	mb();
+	info->IER = UART_IER_MSI;
+
+	/* remember current state of the DCD and CTS bits */
+	current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR);
+
+	IRQ_ports = info;
+
+	info->MCR = 0;
+	if (info->tty->termios->c_cflag & CBAUD)
+	  info->MCR = SER_DTR | SER_RTS;
+	rtsdtr_ctrl(info->MCR);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set up the tty->alt_speed kludge
+	 */
+	if (info->tty) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->tty->alt_speed = 57600;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->tty->alt_speed = 115200;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->tty->alt_speed = 230400;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->tty->alt_speed = 460800;
+	}
+	
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info, 0);
+
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+	
+errout:
+	restore_flags(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+	unsigned long	flags;
+	struct serial_state *state;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d ....\n", info->line);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+	
+	IRQ_ports = NULL;
+	
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	free_irq(IRQ_AMIGA_VERTB, info);
+
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	info->IER = 0;
+	custom.intena = IF_RBF | IF_TBE;
+	mb();
+
+	/* disable break condition */
+	custom.adkcon = AC_UARTBRK;
+	mb();
+	
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		info->MCR &= ~(SER_DTR|SER_RTS);
+	rtsdtr_ctrl(info->MCR);
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct async_struct *info,
+			 struct termios *old_termios)
+{
+	int	quot = 0, baud_base, baud;
+	unsigned cflag, cval = 0;
+	int	bits;
+	unsigned long	flags;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+
+	/* Byte size is always 8 bits plus parity bit if requested */
+
+	cval = 3; bits = 10;
+	if (cflag & CSTOPB) {
+		cval |= 0x04;
+		bits++;
+	}
+	if (cflag & PARENB) {
+		cval |= UART_LCR_PARITY;
+		bits++;
+	}
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+	if (cflag & CMSPAR)
+		cval |= UART_LCR_SPAR;
+#endif
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(info->tty);
+	if (!baud)
+		baud = 9600;	/* B0 transition handled in rs_set_termios */
+	baud_base = info->state->baud_base;
+	if (baud == 38400 &&
+	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		quot = info->state->custom_divisor;
+	else {
+		if (baud == 134)
+			/* Special case since 134 is really 134.5 */
+			quot = (2*baud_base / 269);
+		else if (baud)
+			quot = baud_base / baud;
+	}
+	/* If the quotient is zero refuse the change */
+	if (!quot && old_termios) {
+		info->tty->termios->c_cflag &= ~CBAUD;
+		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+		baud = tty_get_baud_rate(info->tty);
+		if (!baud)
+			baud = 9600;
+		if (baud == 38400 &&
+		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+			quot = info->state->custom_divisor;
+		else {
+			if (baud == 134)
+				/* Special case since 134 is really 134.5 */
+				quot = (2*baud_base / 269);
+			else if (baud)
+				quot = baud_base / baud;
+		}
+	}
+	/* As a last resort, if the quotient is zero, default to 9600 bps */
+	if (!quot)
+		quot = baud_base / 9600;
+	info->quot = quot;
+	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	/* TBD:
+	 * Does clearing IER_MSI imply that we should disbale the VBL interrupt ?
+	 */
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = UART_LSR_OE | UART_LSR_DR;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= UART_LSR_BI;
+	
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignore parity and break indicators, ignore 
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= UART_LSR_OE;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+		info->ignore_status_mask |= UART_LSR_DR;
+	save_flags(flags); cli();
+
+	{
+	  short serper;
+
+	/* Set up the baud rate */
+	  serper = quot - 1;
+
+	/* Enable or disable parity bit */
+
+	if(cval & UART_LCR_PARITY)
+	  serper |= (SERPER_PARENB);
+
+	custom.serper = serper;
+	mb();
+	}
+
+	info->LCR = cval;				/* Save LCR */
+	restore_flags(flags);
+}
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+		return;
+
+	if (!tty || !info->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		restore_flags(flags);
+		return;
+	}
+
+	info->xmit_buf[info->xmit_head++] = ch;
+	info->xmit_head &= SERIAL_XMIT_SIZE-1;
+	info->xmit_cnt++;
+	restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	info->IER |= UART_IER_THRI;
+	custom.intena = IF_SETCLR | IF_TBE;
+	mb();
+	/* set a pending Tx Interrupt, transmitter should restart now */
+	custom.intreq = IF_SETCLR | IF_TBE;
+	mb();
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf || !tmp_buf)
+		return 0;
+
+	save_flags(flags);
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			c = MIN(count,
+				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				    SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			cli();
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			info->xmit_head = ((info->xmit_head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			info->xmit_cnt += c;
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		while (1) {
+			cli();		
+			c = MIN(count,
+				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				    SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0) {
+				restore_flags(flags);
+				break;
+			}
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+			info->xmit_head = ((info->xmit_head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			info->xmit_cnt += c;
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+	}
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+	    !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		cli();
+		custom.intena = IF_SETCLR | IF_TBE;
+		mb();
+		/* set a pending Tx Interrupt, transmitter should restart now */
+		custom.intreq = IF_SETCLR | IF_TBE;
+		mb();
+		restore_flags(flags);
+	}
+	return ret;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	save_flags(flags); cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	restore_flags(flags);
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+        unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+
+	        /* Check this ! */
+	        save_flags(flags);
+		cli();
+		if(!(custom.intenar & IF_TBE)) {
+		    custom.intena = IF_SETCLR | IF_TBE;
+		    mb();
+		    /* set a pending Tx Interrupt, transmitter should restart now */
+		    custom.intreq = IF_SETCLR | IF_TBE;
+		    mb();
+		}
+		restore_flags(flags);
+
+		info->IER |= UART_IER_THRI;
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~SER_RTS;
+
+	save_flags(flags); cli();
+	rtsdtr_ctrl(info->MCR);
+	restore_flags(flags);
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_send_xchar(tty, START_CHAR(tty));
+	}
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= SER_RTS;
+	save_flags(flags); cli();
+	rtsdtr_ctrl(info->MCR);
+	restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct serial_state *state = info->state;
+   
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = state->type;
+	tmp.line = state->line;
+	tmp.port = state->port;
+	tmp.irq = state->irq;
+	tmp.flags = state->flags;
+	tmp.xmit_fifo_size = state->xmit_fifo_size;
+	tmp.baud_base = state->baud_base;
+	tmp.close_delay = state->close_delay;
+	tmp.closing_wait = state->closing_wait;
+	tmp.custom_divisor = state->custom_divisor;
+	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+ 	struct serial_state old_state, *state;
+	unsigned int		change_irq,change_port;
+	int 			retval = 0;
+
+	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+		return -EFAULT;
+	state = info->state;
+	old_state = *state;
+  
+	change_irq = new_serial.irq != state->irq;
+	change_port = (new_serial.port != state->port);
+	if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size))
+	  return -EINVAL;
+  
+	if (!serial_isroot()) {
+		if ((new_serial.baud_base != state->baud_base) ||
+		    (new_serial.close_delay != state->close_delay) ||
+		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (state->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		state->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (new_serial.baud_base < 9600)
+		return -EINVAL;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	state->baud_base = new_serial.baud_base;
+	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
+	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+		       (info->flags & ASYNC_INTERNAL_FLAGS));
+	state->custom_divisor = new_serial.custom_divisor;
+	state->close_delay = new_serial.close_delay * HZ/100;
+	state->closing_wait = new_serial.closing_wait * HZ/100;
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	
+check_and_exit:
+	if (info->flags & ASYNC_INITIALIZED) {
+		if (((old_state.flags & ASYNC_SPD_MASK) !=
+		     (state->flags & ASYNC_SPD_MASK)) ||
+		    (old_state.custom_divisor != state->custom_divisor)) {
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				info->tty->alt_speed = 57600;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				info->tty->alt_speed = 115200;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				info->tty->alt_speed = 230400;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				info->tty->alt_speed = 460800;
+			change_speed(info, 0);
+		}
+	} else
+		retval = startup(info);
+	return retval;
+}
+
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	status = custom.serdatr;
+	mb();
+	restore_flags(flags);
+	result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0);
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+	unsigned long flags;
+
+	control = info->MCR;
+	save_flags(flags); cli();
+	status = ciab.pra;
+	restore_flags(flags);
+	result =  ((control & SER_RTS) ? TIOCM_RTS : 0)
+		| ((control & SER_DTR) ? TIOCM_DTR : 0)
+		| (!(status  & SER_DCD) ? TIOCM_CAR : 0)
+		| (!(status  & SER_DSR) ? TIOCM_DSR : 0)
+		| (!(status  & SER_CTS) ? TIOCM_CTS : 0);
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	unsigned int arg;
+	unsigned long flags;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case TIOCMBIS: 
+	        if (arg & TIOCM_RTS)
+			info->MCR |= SER_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= SER_DTR;
+		break;
+	case TIOCMBIC:
+	        if (arg & TIOCM_RTS)
+			info->MCR &= ~SER_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~SER_DTR;
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(SER_RTS | SER_DTR))
+			     | ((arg & TIOCM_RTS) ? SER_RTS : 0)
+			     | ((arg & TIOCM_DTR) ? SER_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	save_flags(flags); cli();
+	rtsdtr_ctrl(info->MCR);
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_break"))
+		return;
+
+	save_flags(flags); cli();
+	if (break_state == -1)
+	  custom.adkcon = AC_SETCLR | AC_UARTBRK;
+	else
+	  custom.adkcon = AC_UARTBRK;
+	mb();
+	restore_flags(flags);
+}
+
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct async_icount cprev, cnow;	/* kernel counter temps */
+	struct serial_icounter_struct icount;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERCONFIG:
+			return 0;
+
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct async_struct *) arg,
+					 info, sizeof(struct async_struct)))
+				return -EFAULT;
+			return 0;
+				
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+ 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		case TIOCMIWAIT:
+			save_flags(flags); cli();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			restore_flags(flags);
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				save_flags(flags); cli();
+				cnow = info->state->icount; /* atomic copy */
+				restore_flags(flags);
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+
+		/* 
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			save_flags(flags); cli();
+			cnow = info->state->icount;
+			restore_flags(flags);
+			icount.cts = cnow.cts;
+			icount.dsr = cnow.dsr;
+			icount.rng = cnow.rng;
+			icount.dcd = cnow.dcd;
+			icount.rx = cnow.rx;
+			icount.tx = cnow.tx;
+			icount.frame = cnow.frame;
+			icount.overrun = cnow.overrun;
+			icount.parity = cnow.parity;
+			icount.brk = cnow.brk;
+			icount.buf_overrun = cnow.buf_overrun;
+			
+			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+				return -EFAULT;
+			return 0;
+		case TIOCSERGWILD:
+		case TIOCSERSWILD:
+			/* "setserial -W" is called in Debian boot */
+			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	unsigned int cflag = tty->termios->c_cflag;
+	
+	if (   (cflag == old_termios->c_cflag)
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info, old_termios);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+	    !(cflag & CBAUD)) {
+		info->MCR &= ~(SER_DTR|SER_RTS);
+		save_flags(flags); cli();
+		rtsdtr_ctrl(info->MCR);
+		restore_flags(flags);
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    (cflag & CBAUD)) {
+		info->MCR |= SER_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) || 
+		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->MCR |= SER_RTS;
+		}
+		save_flags(flags); cli();
+		rtsdtr_ctrl(info->MCR);
+		restore_flags(flags);
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+
+#if 0
+	/*
+	 * No need to wake up processes in open wait, since they
+	 * sample the CLOCAL flag once, and don't recheck it.
+	 * XXX  It's not clear whether the current behavior is correct
+	 * or not.  Hence, this may change.....
+	 */
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->read_status_mask &= ~UART_LSR_DR;
+	if (info->flags & ASYNC_INITIALIZED) {
+	        /* disable receive interrupts */
+	        custom.intena = IF_RBF;
+		mb();
+		/* clear any pending receive interrupt */
+		custom.intreq = IF_RBF;
+		mb();
+
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		rs_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+	restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	int lsr;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+	if (info->xmit_fifo_size == 0)
+		return; /* Just in case.... */
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 * 
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout)
+	  char_time = MIN(char_time, timeout);
+	/*
+	 * If the transmitter hasn't cleared in twice the approximate
+	 * amount of time to send the entire FIFO, it probably won't
+	 * ever clear.  This assumes the UART isn't doing flow
+	 * control, which is currently the case.  Hence, if it ever
+	 * takes longer than info->timeout, this is probably due to a
+	 * UART bug of some kind.  So, we clamp the timeout parameter at
+	 * 2*info->timeout.
+	 */
+	if (!timeout || timeout > 2*info->timeout)
+		timeout = 2*info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+	while(!((lsr = custom.serdatr) & SDR_TSRE)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("serdatr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+	}
+	current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_hangup(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state = info->state;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	state = info->state;
+	
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct async_struct *info)
+{
+#ifdef DECLARE_WAITQUEUE
+	DECLARE_WAITQUEUE(wait, current);
+#else
+	struct wait_queue wait = { current, NULL };
+#endif
+	struct serial_state *state = info->state;
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+	unsigned long	flags;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       state->line, state->count);
+#endif
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		state->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		save_flags(flags); cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+		        rtsdtr_ctrl(SER_DTR|SER_RTS);
+		restore_flags(flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (!(ciab.pra & SER_DCD)) ))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, state->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (extra_count)
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, state->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	sstate->count++;
+	if (sstate->info) {
+		*ret_info = sstate->info;
+		return 0;
+	}
+	info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+	if (!info) {
+		sstate->count--;
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(struct async_struct));
+#ifdef DECLARE_WAITQUEUE
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+#endif
+	info->magic = SERIAL_MAGIC;
+	info->port = sstate->port;
+	info->flags = sstate->flags;
+	info->xmit_fifo_size = sstate->xmit_fifo_size;
+	info->line = line;
+	info->tqueue.routine = do_softint;
+	info->tqueue.data = info;
+	info->state = sstate;
+	if (sstate->info) {
+		kfree_s(info, sizeof(struct async_struct));
+		*ret_info = sstate->info;
+		return 0;
+	}
+	*ret_info = sstate->info = info;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct async_struct	*info;
+	int 			retval, line;
+	unsigned long		page;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+	tty->driver_data = info;
+	info->tty = tty;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->state->count);
+#endif
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	if (!tmp_buf) {
+		page = get_free_page(GFP_KERNEL);
+		if (!page) {
+			return -ENOMEM;
+		}
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval) {
+		return retval;
+	}
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->state->count == 1) &&
+	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else 
+			*tty->termios = info->state->callout_termios;
+		change_speed(info, 0);
+	}
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+	struct async_struct *info = state->info, scr_info;
+	char	stat_buf[30], control, status;
+	int	ret;
+	unsigned long flags;
+
+	ret = sprintf(buf, "%d: uart:amiga_builtin",state->line);
+
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info;	/* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->flags = state->flags;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	save_flags(flags); cli();
+	status = ciab.pra;
+	control = info ? info->MCR : status;
+	restore_flags(flags); 
+	
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if(!(control & SER_RTS))
+		strcat(stat_buf, "|RTS");
+	if(!(status & SER_CTS))
+		strcat(stat_buf, "|CTS");
+	if(!(control & SER_DTR))
+		strcat(stat_buf, "|DTR");
+	if(!(status & SER_DSR))
+		strcat(stat_buf, "|DSR");
+	if(!(status & SER_DCD))
+		strcat(stat_buf, "|CD");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			       state->baud_base / info->quot);
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		      state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	return ret;
+}
+
+int rs_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int len = 0, l;
+	off_t	begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+	l = line_info(page + len, &rs_table[0]);
+	len += l;
+	if (len+begin > off+count)
+	  goto done;
+	if (len+begin < off) {
+	  begin += len;
+	  len = 0;
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (begin-off);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+
+int register_serial(struct serial_struct *req);
+void unregister_serial(int line);
+
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+int __init rs_init(void)
+{
+	unsigned long flags;
+	struct serial_state * state;
+
+	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
+		return -ENODEV;
+
+	init_bh(SERIAL_BH, do_serial_bh);
+
+	IRQ_ports = NULL;
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "amiserial";
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = 1;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.put_char = rs_put_char;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+	serial_driver.break_ctl = rs_break;
+	serial_driver.send_xchar = rs_send_xchar;
+	serial_driver.wait_until_sent = rs_wait_until_sent;
+	serial_driver.read_proc = rs_read_proc;
+	
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	state = rs_table;
+	state->magic = SSTATE_MAGIC;
+	state->port = (int)&custom.serdatr; /* Just to give it a value */
+	state->line = 0;
+	state->custom_divisor = 0;
+	state->close_delay = 5*HZ/10;
+	state->closing_wait = 30*HZ;
+	state->callout_termios = callout_driver.init_termios;
+	state->normal_termios = serial_driver.init_termios;
+	state->icount.cts = state->icount.dsr = 
+	  state->icount.rng = state->icount.dcd = 0;
+	state->icount.rx = state->icount.tx = 0;
+	state->icount.frame = state->icount.parity = 0;
+	state->icount.overrun = state->icount.brk = 0;
+	/*
+	if(state->port && check_region(state->port,REGION_LENGTH(state)))
+	  continue;
+	*/
+
+	printk(KERN_INFO "ttyS%02d is the amiga builtin serial port\n",
+		       state->line);
+
+	/* Hardware set up */
+
+	state->baud_base = amiga_colorclock;
+	state->xmit_fifo_size = 1;
+
+	save_flags (flags);
+	cli();
+
+	/* set ISRs, and then disable the rx interrupts */
+	request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
+	request_irq(IRQ_AMIGA_RBF, ser_rx_int, SA_INTERRUPT, "serial RX", state);
+
+	/* turn off Rx and Tx interrupts */
+	custom.intena = IF_RBF | IF_TBE;
+	mb();
+
+	/* clear any pending interrupt */
+	custom.intreq = IF_RBF | IF_TBE;
+	mb();
+
+	restore_flags (flags);
+
+	/*
+	 * set the appropriate directions for the modem control flags,
+	 * and clear RTS and DTR
+	 */
+	ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
+	ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
+
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return rs_init();
+}
+
+void cleanup_module(void) 
+{
+	unsigned long flags;
+	int e1, e2;
+	struct async_struct *info;
+
+	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+	save_flags(flags);
+	cli();
+        remove_bh(SERIAL_BH);
+	if ((e1 = tty_unregister_driver(&serial_driver)))
+		printk("SERIAL: failed to unregister serial driver (%d)\n",
+		       e1);
+	if ((e2 = tty_unregister_driver(&callout_driver)))
+		printk("SERIAL: failed to unregister callout driver (%d)\n", 
+		       e2);
+	restore_flags(flags);
+
+	info = rs_table[0].info;
+	if (info) {
+	  rs_table[0].info = NULL;
+	  kfree_s(info, sizeof(struct async_struct));
+	}
+
+	if (tmp_buf) {
+		free_page((unsigned long) tmp_buf);
+		tmp_buf = NULL;
+	}
+}
+#endif /* MODULE */
+
+/*
+  Local variables:
+  compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce  -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
+  End:
+*/
diff -u --recursive --new-file v2.3.44/linux/drivers/char/mac_SCC.c linux/drivers/char/mac_SCC.c
--- v2.3.44/linux/drivers/char/mac_SCC.c	Fri Dec 18 09:36:05 1998
+++ linux/drivers/char/mac_SCC.c	Wed Dec 31 16:00:00 1969
@@ -1,1529 +0,0 @@
-/*
- * mac_SCC.c: m68k version of
- *
- * macserial.c: Serial port driver for Power Macintoshes.
- *		Extended for the 68K mac by Alan Cox.
- *              Rewritten to m68k serial design by Michael Schmitz
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/*
- * Design note for the m68k rewrite:
- * The structure of the m68k serial code requires separation of the low-level
- * functions that talk directly to the hardware from the Linux serial driver 
- * code interfacing to the tty layer. The reason for this separation is simply
- * the fact that the m68k serial hardware is, unlike the i386, based on a 
- * variety of chips, and the rs_* serial routines need to be shared.
- *
- * I've tried to make consistent use of the async_struct info populated in the
- * midlevel code, and introduced an async_private struct to hold the Macintosh 
- * SCC internals (this was added to the async_struct for the PowerMac driver).
- * Exception: the console and kgdb hooks still use the zs_soft[] data, and this
- * is still filled in by the probe_sccs() routine, which provides some data 
- * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so 
- * the console/kgdb stuff probably won't work before proper serial init, and 
- * I have to rely on keeping info and zs_soft consistent at least for the 
- * console/kgdb port.
- *
- * Update (16-11-97): The SCC interrupt handling was suffering from the problem
- * that the autovector SCC interrupt was registered only once, hence only one
- * async_struct was passed to the interrupt function and only interrupts from 
- * the corresponding channel could be handled (yes, major design flaw).
- * The autovector interrupt is now registered by the main interrupt initfunc, 
- * and uses a handler that will call the registered SCC specific interrupts in 
- * turn. The SCC init has to register these as machspec interrupts now, as is 
- * done for the VIA interrupts elsewhere.
- */
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/config.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-
-#include <asm/uaccess.h>
-#include <asm/setup.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/macints.h>
-#ifndef CONFIG_MAC
-#include <asm/prom.h>
-#endif
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/bitops.h>
-#include <asm/hwtest.h>
-
-#include "mac_SCC.h"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL	2		/* Max number of ZS chips supported */
-#define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
-
-#ifdef CONFIG_MAC
-/*
- *	All the Macintosh 68K boxes that have an MMU also have hardware
- *	recovery delays.
- */
-#define RECOVERY_DELAY
-#else
-/* On PowerMacs, the hardware takes care of the SCC recovery time,
-   but we need the eieio to make sure that the accesses occur
-   in the order we want. */
-#define RECOVERY_DELAY	eieio()
-#endif
-
-struct mac_zschannel *zs_kgdbchan;
-struct mac_zschannel zs_channels[NUM_CHANNELS];
-
-struct m68k_async_struct  zs_soft[NUM_CHANNELS];
-struct m68k_async_private zs_soft_private[NUM_CHANNELS];
-int zs_channels_found;
-struct m68k_async_struct *zs_chain;	/* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-/** struct tty_struct *zs_constty; **/
-
-/* Console hooks... */
-static int zs_cons_chanout = 0;
-static int zs_cons_chanin = 0;
-struct m68k_async_struct  *zs_consinfo = 0;
-struct mac_zschannel *zs_conschan;
-
-static unsigned char kgdb_regs[16] = {
-	0, 0, 0,		/* write 0, 1, 2 */
-	(Rx8 | RxENABLE),	/* write 3 */
-	(X16CLK | SB1 | PAR_EVEN), /* write 4 */
-	(Tx8 | TxENAB),		/* write 5 */
-	0, 0, 0,		/* write 6, 7, 8 */
-	(NV),			/* write 9 */
-	(NRZ),			/* write 10 */
-	(TCBR | RCBR),		/* write 11 */
-	1, 0,			/* 38400 baud divisor, write 12 + 13 */
-	(BRENABL),		/* write 14 */
-	(DCDIE)			/* write 15 */
-};
-
-#define ZS_CLOCK         3686400 	/* Z8530 RTxC input clock rate */
-
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-#define _INLINE_ inline
-
-static void probe_sccs(void);
-
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
-
-/***************************** Prototypes *****************************/
-
-static void SCC_init_port( struct m68k_async_struct *info, int type, int channel );
-#if 0
-#ifdef MODULE
-static void SCC_deinit_port( struct m68k_async_struct *info, int channel );
-#endif
-#endif
-
-/* FIXME !!! Currently, only autovector interrupt used! */
-#if 0
-static void SCC_rx_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_tx_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_stat_int (int irq, void *data, struct pt_regs *fp);
-static void SCC_ri_int (int irq, void *data, struct pt_regs *fp);
-#endif
-
-static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct
-                           *tty, struct file *file );
-static void SCC_init( struct m68k_async_struct *info );
-static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr );
-static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag );
-static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base,
-				    int divisor );
-static void SCC_change_speed( struct m68k_async_struct *info );
-#if 0
-static int SCC_clocksrc( unsigned baud_base, unsigned channel );
-#endif
-static void SCC_throttle( struct m68k_async_struct *info, int status );
-static void SCC_set_break( struct m68k_async_struct *info, int break_flag );
-static void SCC_get_serial_info( struct m68k_async_struct *info, struct
-				serial_struct *retinfo );
-static unsigned int SCC_get_modem_info( struct m68k_async_struct *info );
-static int SCC_set_modem_info( struct m68k_async_struct *info, int new_dtr, int
-			      new_rts );
-static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct
-		     m68k_async_struct *info, unsigned int cmd, unsigned long arg );
-static void SCC_stop_receive (struct m68k_async_struct *info);
-static int SCC_trans_empty (struct m68k_async_struct *info);
-
-/************************* End of Prototypes **************************/
-
-
-static SERIALSWITCH SCC_switch = {
-	SCC_init, SCC_deinit, SCC_enab_tx_int,
-	SCC_check_custom_divisor, SCC_change_speed,
-	SCC_throttle, SCC_set_break,
-	SCC_get_serial_info, SCC_get_modem_info,
-	SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty,
-	SCC_check_open
-};
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 0 };
-
-/* 
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char read_zsreg(struct mac_zschannel *channel,
-				       unsigned char reg)
-{
-	unsigned char retval;
-
-	if (reg != 0) {
-		*channel->control = reg;
-		RECOVERY_DELAY;
-	}
-	retval = *channel->control;
-	RECOVERY_DELAY;
-	return retval;
-}
-
-static inline void write_zsreg(struct mac_zschannel *channel,
-			       unsigned char reg, unsigned char value)
-{
-	if (reg != 0) {
-		*channel->control = reg;
-		RECOVERY_DELAY;
-	}
-	*channel->control = value;
-	RECOVERY_DELAY;
-	return;
-}
-
-static inline unsigned char read_zsdata(struct mac_zschannel *channel)
-{
-	unsigned char retval;
-
-	retval = *channel->data;
-	RECOVERY_DELAY;
-	return retval;
-}
-
-static inline void write_zsdata(struct mac_zschannel *channel,
-				unsigned char value)
-{
-	*channel->data = value;
-	RECOVERY_DELAY;
-	return;
-}
-
-static inline void load_zsregs(struct mac_zschannel *channel,
-			       unsigned char *regs)
-{
-	ZS_CLEARERR(channel);
-	ZS_CLEARFIFO(channel);
-	/* Load 'em up */
-	write_zsreg(channel, R4, regs[R4]);
-	write_zsreg(channel, R10, regs[R10]);
-	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
-	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-	write_zsreg(channel, R1, regs[R1]);
-	write_zsreg(channel, R9, regs[R9]);
-	write_zsreg(channel, R11, regs[R11]);
-	write_zsreg(channel, R12, regs[R12]);
-	write_zsreg(channel, R13, regs[R13]);
-	write_zsreg(channel, R14, regs[R14]);
-	write_zsreg(channel, R15, regs[R15]);
-	write_zsreg(channel, R3, regs[R3]);
-	write_zsreg(channel, R5, regs[R5]);
-	return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set)
-{
-	if (set)
-		ss->private->curregs[5] |= (RTS | DTR);
-	else
-		ss->private->curregs[5] &= ~(RTS | DTR);
-	write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]);
-	return;
-}
-
-static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps)
-{
-	int brg;
-
-	if (intson) {
-		kgdb_regs[R1] = INT_ALL_Rx;
-		kgdb_regs[R9] |= MIE;
-	} else {
-		kgdb_regs[R1] = 0;
-		kgdb_regs[R9] &= ~MIE;
-	}
-	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
-	kgdb_regs[R12] = brg;
-	kgdb_regs[R13] = brg >> 8;
-	load_zsregs(ss->private->zs_channel, kgdb_regs);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct m68k_async_struct *ss)
-{
-	struct mac_zschannel *channel = ss->private->zs_channel;
-	int brg;
-
-	/* The baud rate is split up between two 8-bit registers in
-	 * what is termed 'BRG time constant' format in my docs for
-	 * the chip, it is a function of the clk rate the chip is
-	 * receiving which happens to be constant.
-	 */
-	brg = (read_zsreg(channel, 13) << 8);
-	brg |= read_zsreg(channel, 12);
-	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void SCC_recv_clear(struct mac_zschannel *zsc)
-{
-	write_zsreg(zsc, 0, ERR_RES);
-	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-extern void breakpoint(void);  /* For the KGDB frame character */
-
-static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info,
-				   struct pt_regs *regs)
-{
-	struct tty_struct *tty = info->tty;
-	unsigned char ch, stat, flag;
-
-	while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) {
-
-		stat = read_zsreg(info->private->zs_channel, R1);
-		ch = read_zsdata(info->private->zs_channel);
-
-#ifdef SCC_DEBUG
-		printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch);
-#endif
-
-#if 0	/* KGDB not yet supported */
-		/* Look for kgdb 'stop' character, consult the gdb documentation
-		 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
-		 * to see how all this works.
-		 */
-		if ((info->kgdb_channel) && (ch =='\003')) {
-			breakpoint();
-			continue;
-		}
-#endif
-
-		if (!tty)
-			continue;
-
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-			tty_flip_buffer_push(tty);
-		
-		if (stat & Rx_OVR) {
-			flag = TTY_OVERRUN;
-			/* reset the error indication */
-			write_zsreg(info->private->zs_channel, 0, ERR_RES);
-		} else if (stat & FRM_ERR) {
-			/* this error is not sticky */
-			flag = TTY_FRAME;
-		} else if (stat & PAR_ERR) {
-			flag = TTY_PARITY;
-			/* reset the error indication */
-			write_zsreg(info->private->zs_channel, 0, ERR_RES);
-		} else
-			flag = 0;
-
-		if (tty->flip.buf_num 
-		    && tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#ifdef SCC_DEBUG_OVERRUN
-			printk("mac_SCC: flip buffer overrun!\n");
-#endif
-			return;
-		}
-
-		if (!tty->flip.buf_num 
-		    && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) {
-			printk("mac_SCC: double flip buffer overrun!\n");
-			return;
-		}
-
-		tty->flip.count++;
-		*tty->flip.flag_buf_ptr++ = flag;
-		*tty->flip.char_buf_ptr++ = ch;
-		info->icount.rx++;
-		tty_flip_buffer_push(tty);
-	}
-#if 0
-clear_and_exit:
-	SCC_recv_clear(info->private->zs_channel);
-#endif
-}
-
-/* that's SCC_enable_tx_int, basically */
-
-static void transmit_chars(struct m68k_async_struct *info)
-{
-	if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0)
-		return;
-	info->private->tx_active = 0;
-
-	if (info->x_char) {
-		/* Send next char */
-		write_zsdata(info->private->zs_channel, info->x_char);
-		info->x_char = 0;
-		info->private->tx_active = 1;
-		return;
-	}
-
-	if ((info->xmit_cnt <= 0) || info->tty->stopped 
-	     || info->private->tx_stopped) {
-		write_zsreg(info->private->zs_channel, 0, RES_Tx_P);
-		return;
-	}
-
-	/* Send char */
-	write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]);
-	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-	info->icount.tx++;
-	info->xmit_cnt--;
-	info->private->tx_active = 1;
-
-	if (info->xmit_cnt < WAKEUP_CHARS)
-		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info)
-{
-	unsigned char status;
-
-	/* Get status from Read Register 0 */
-	status = read_zsreg(info->private->zs_channel, 0);
-
-	/* Check for DCD transitions */
-	if (((status ^ info->private->read_reg_zero) & DCD) != 0
-	    && info->tty && C_CLOCAL(info->tty)) {
-		if (status & DCD) {
-			wake_up_interruptible(&info->open_wait);
-		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
-			if (info->tty)
-				tty_hangup(info->tty);
-		}
-	}
-
-	/* Check for CTS transitions */
-	if (info->tty && C_CRTSCTS(info->tty)) {
-		/*
-		 * For some reason, on the Power Macintosh,
-		 * it seems that the CTS bit is 1 when CTS is
-		 * *negated* and 0 when it is asserted.
-		 * The DCD bit doesn't seem to be inverted
-		 * like this.
-		 */
-		if ((status & CTS) == 0) {
-			if (info->private->tx_stopped) {
-				info->private->tx_stopped = 0;
-				if (!info->private->tx_active)
-					transmit_chars(info);
-			}
-		} else {
-			info->private->tx_stopped = 1;
-		}
-	}
-
-	/* Clear status condition... */
-	write_zsreg(info->private->zs_channel, 0, RES_EXT_INT);
-	info->private->read_reg_zero = status;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-	struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id;
-	unsigned char zs_intreg;
-	int shift;
-
-	/* NOTE: The read register 3, which holds the irq status,
-	 *       does so for both channels on each chip.  Although
-	 *       the status value itself must be read from the A
-	 *       channel and is only valid when read from channel A.
-	 *       Yes... broken hardware...
-	 */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
-#ifdef SCC_DEBUG
-	printk("mac_SCC: interrupt; port: %lx channel: %lx \n", 
-		info->port, info->private->zs_channel);
-#endif
-
-	if (info->private->zs_chan_a == info->private->zs_channel)
-		shift = 3;	/* Channel A */
-	else
-		shift = 0;	/* Channel B */
-
-	for (;;) {
-		zs_intreg = read_zsreg(info->private->zs_chan_a, 3);
-#ifdef SCC_DEBUG
-		printk("mac_SCC: status %x shift %d shifted %x \n", 
-		zs_intreg, shift, zs_intreg >> shift);
-#endif
-		zs_intreg = zs_intreg >> shift;
-		if ((zs_intreg & CHAN_IRQMASK) == 0)
-			break;
-
-		if (zs_intreg & CHBRxIP)
-			receive_chars(info, regs);
-		if (zs_intreg & CHBTxIP)
-			transmit_chars(info);
-		if (zs_intreg & CHBEXT)
-			status_handle(info);
-	}
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-
-static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag )
-{
-	unsigned long flags;
-
-	if (enab_flag) {
-#if 0
-		save_flags(flags); cli();
-		if (info->private->curregs[5] & TxENAB) {
-			info->private->curregs[5] &= ~TxENAB;
-			info->private->pendregs[5] &= ~TxENAB;
-			write_zsreg(info->private->zs_channel, 5, 
-				    info->private->curregs[5]);
-		}
-		restore_flags(flags);
-#endif
-	/* FIXME: should call transmit_chars here ??? */
-		transmit_chars(info);
-	} else {
-	save_flags(flags); cli();
-#if 0
-		if (  info->xmit_cnt && info->xmit_buf && 
-		    !(info->private->curregs[5] & TxENAB)) {
-			info->private->curregs[5] |= TxENAB;
-			info->private->pendregs[5] = info->private->curregs[5];
-			write_zsreg(info->private->zs_channel, 5, 
-				    info->private->curregs[5]);
-		}
-#else
-		if ( info->xmit_cnt && info->xmit_buf && 
-		    !info->private->tx_active) {
-			transmit_chars(info);
-		}
-#endif
-		restore_flags(flags);	
-	}
-
-}
-
-#if 0
-/*
- * leftover from original driver ...
- */
-static int SCC_startup(struct m68k_async_struct * info)
-{
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
-#endif
-
-	/*
-	 * Clear the receive FIFO.
-	 */
-	ZS_CLEARFIFO(info->private->zs_channel);
-	info->xmit_fifo_size = 1;
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-	write_zsreg(info->private->zs_channel, 0, ERR_RES);
-	write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
-
-	/*
-	 * Turn on RTS and DTR.
-	 */
-	zs_rtsdtr(info, 1);
-
-	/*
-	 * Finally, enable sequencing and interrupts
-	 */
-	info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 
-				    | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
-	info->private->pendregs[1] = info->private->curregs[1];
-	info->private->curregs[3] |= (RxENABLE | Rx8);
-	info->private->pendregs[3] = info->private->curregs[3];
-	info->private->curregs[5] |= (TxENAB | Tx8);
-	info->private->pendregs[5] = info->private->curregs[5];
-	info->private->curregs[9] |= (NV | MIE);
-	info->private->pendregs[9] = info->private->curregs[9];
-	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
-	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
-	write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
-
-	/*
-	 * Set the speed of the serial port
-	 */
-	SCC_change_speed(info);
-
-	/* Save the current value of RR0 */
-	info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
-
-	restore_flags(flags);
-	return 0;
-}
-#endif
-
-/* FIXME: are these required ?? */
-static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,
-			  struct file *file )
-{
-	/* check on the basis of info->whatever ?? */
-	if (info->private->kgdb_channel || info->private->is_cons)
-		return -EBUSY;
-	return( 0 );
-}
-
-static void SCC_init( struct m68k_async_struct *info )
-{
-	/* FIXME: init currently done in probe_sccs() */
-
-	/* BUT: startup part needs to be done here! */
-
-#ifdef SCC_DEBUG
-	printk("mac_SCC: init, info %lx, info->port %lx  \n", info, info->port);
-#endif
-	/*
-	 * Clear the receive FIFO.
-	 */
-	ZS_CLEARFIFO(info->private->zs_channel);
-	info->xmit_fifo_size = 1;
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-	write_zsreg(info->private->zs_channel, 0, ERR_RES);
-	write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
-
-	/*
-	 * Turn on RTS and DTR.
-	 */
-	zs_rtsdtr(info, 1);
-
-	/*
-	 * Finally, enable sequencing and interrupts
-	 */
-	info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 
-				    | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
-	info->private->pendregs[1] = info->private->curregs[1];
-	info->private->curregs[3] |= (RxENABLE | Rx8);
-	info->private->pendregs[3] = info->private->curregs[3];
-	info->private->curregs[5] |= (TxENAB | Tx8);
-	info->private->pendregs[5] = info->private->curregs[5];
-	info->private->curregs[9] |= (NV | MIE);
-	info->private->pendregs[9] = info->private->curregs[9];
-	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
-	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
-	write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
-
-	/*
-	 * Set the speed of the serial port - done in startup() !!
-	 */
-#if 0
-	SCC_change_speed(info);
-#endif
-
-	/* Save the current value of RR0 */
-	info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
-
-}
-
-static void SCC_init_port( struct m68k_async_struct *info, int type, int channel )
-{
-	static int got_autovector = 0;
-
-#ifdef SCC_DEBUG
-	printk("mac_SCC: init_port, info %x \n", info);
-#endif
-	info->sw = &SCC_switch;
-	info->private = &zs_soft_private[channel];
-	info->private->zs_channel = &zs_channels[channel];
-	info->irq = IRQ4;
-	info->private->clk_divisor = 16;
-	info->private->zs_baud = get_zsbaud(info);
-	info->port = (int) info->private->zs_channel->control;
-
-	/*
-	 * MSch: Extended interrupt scheme:
-	 * The generic m68k interrupt code can't use multiple handlers for
-	 * the same interrupt source (no chained interrupts).
-	 * We have to plug in a 'master' interrupt handler instead, calling 
-	 * mac_SCC_interrupt with the proper arguments ...
-	 */
-
-	if (!got_autovector) {
-		if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))
-			panic("macserial: can't get irq %d", IRQ4);
-#ifdef SCC_DEBUG
-		printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",
-			IRQ4, channel, info);
-#endif
-		got_autovector = 1;
-	}
-
-	if (info->private->zs_chan_a == info->private->zs_channel) {
-		/* Channel A */
-		if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))
-			panic("mac_SCC: can't get irq %d", IRQ_SCCA);
-#ifdef SCC_DEBUG
-		printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",
-			IRQ_SCCA, channel, info);
-#endif
-	} else {
-		/* Channel B */
-		if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))
-			panic("mac_SCC: can't get irq %d", IRQ_SCCB);
-#ifdef SCC_DEBUG
-		printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n", 
-			IRQ_SCCB, channel, info);
-#endif
-	}
-
-	/* If console serial line, then enable interrupts. */
-	if (info->private->is_cons) {
-		printk("mac_SCC: console line %d; enabling interrupt!\n", info->line);
-		write_zsreg(info->private->zs_channel, R1,
-			    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
-		write_zsreg(info->private->zs_channel, R9, (NV | MIE));
-		write_zsreg(info->private->zs_channel, R10, (NRZ));
-		write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));
-		write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));
-	}
-	/* If this is the kgdb line, enable interrupts because we
-	 * now want to receive the 'control-c' character from the
-	 * client attached to us asynchronously.
-	 */
-	if (info->private->kgdb_channel) {
-		printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line);
-		kgdb_chaninit(info, 1, info->private->zs_baud);
-	}
-	/* Report settings (in m68kserial.c) */
-#ifndef CONFIG_MAC
-	printk("ttyS%d at 0x%08x (irq = %d)", info->line, 
-		       info->port, info->irq);
-	printk(" is a Z8530 SCC\n");
-#endif
-
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr)
-{
-	unsigned long	flags;
-
-	save_flags(flags); cli(); /* Disable interrupts */
-	
-	info->private->pendregs[1] = info->private->curregs[1] = 0;
-	write_zsreg(info->private->zs_channel, 1, 0);	/* no interrupts */
-
-	info->private->curregs[3] &= ~RxENABLE;
-	info->private->pendregs[3] = info->private->curregs[3];
-	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
-
-	info->private->curregs[5] &= ~TxENAB;
-
-	if (!leave_dtr)
-		info->private->curregs[5] &= ~(DTR | RTS);
-	else
-		info->private->curregs[5] &= ~(RTS);
-
-	info->private->pendregs[5] = info->private->curregs[5];
-	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
-
-	restore_flags(flags);
-}
-
-/* FIXME !!! */
-static int SCC_check_custom_divisor( struct m68k_async_struct *info,
-				    int baud_base, int divisor )
-{
-	return 0;
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void SCC_change_speed(struct m68k_async_struct *info)
-{
-	unsigned short port;
-	unsigned cflag;
-	int	i;
-	int	brg;
-	unsigned long flags;
-
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
-	if (!(port = info->port))
-		return;
-	i = cflag & CBAUD;
-
-	if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {
-		/* speed == 0 -> drop DTR */
-		save_flags(flags);
-		cli();
-		info->private->curregs[5] &= ~(DTR | RTS);
-		write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
-		restore_flags(flags);
-		return;
-	}
-
-
-	if (i & CBAUDEX) {
-		/* XXX CBAUDEX is not obeyed.
-		 * It is impossible at a 32bits PPC.  XXX??
-		 * But we have to report this to user ... someday.
-		 */
-		i = B9600;
-	}
-
-	save_flags(flags); cli();
-	info->private->zs_baud = baud_table[i];
-	info->private->clk_divisor = 16;
-
-	info->private->curregs[4] = X16CLK;
-	info->private->curregs[11] = TCBR | RCBR;
-	brg = BPS_TO_BRG(info->private->zs_baud, 
-			 ZS_CLOCK/info->private->clk_divisor);
-	info->private->curregs[12] = (brg & 255);
-	info->private->curregs[13] = ((brg >> 8) & 255);
-	info->private->curregs[14] = BRENABL;
-
-	/* byte size and parity */
-	info->private->curregs[3] &= ~RxNBITS_MASK;
-	info->private->curregs[5] &= ~TxNBITS_MASK;
-	switch (cflag & CSIZE) {
-	case CS5:
-		info->private->curregs[3] |= Rx5;
-		info->private->curregs[5] |= Tx5;
-		break;
-	case CS6:
-		info->private->curregs[3] |= Rx6;
-		info->private->curregs[5] |= Tx6;
-		break;
-	case CS7:
-		info->private->curregs[3] |= Rx7;
-		info->private->curregs[5] |= Tx7;
-		break;
-	case CS8:
-	default: /* defaults to 8 bits */
-		info->private->curregs[3] |= Rx8;
-		info->private->curregs[5] |= Tx8;
-		break;
-	}
-	info->private->pendregs[3] = info->private->curregs[3];
-	info->private->pendregs[5] = info->private->curregs[5];
-
-	info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-	if (cflag & CSTOPB) {
-		info->private->curregs[4] |= SB2;
-	} else {
-		info->private->curregs[4] |= SB1;
-	}
-	if (cflag & PARENB) {
-		info->private->curregs[4] |= PAR_ENA;
-	}
-	if (!(cflag & PARODD)) {
-		info->private->curregs[4] |= PAR_EVEN;
-	}
-	info->private->pendregs[4] = info->private->curregs[4];
-
-	info->private->curregs[15] &= ~(DCDIE | CTSIE);
-	if (!(cflag & CLOCAL)) {
-		info->private->curregs[15] |= DCDIE;
-	}
-	if (cflag & CRTSCTS) {
-		info->private->curregs[15] |= CTSIE;
-		if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)
-			info->private->tx_stopped = 1;
-	} else
-		info->private->tx_stopped = 0;
-	info->private->pendregs[15] = info->private->curregs[15];
-
-	/* Load up the new values */
-	load_zsregs(info->private->zs_channel, info->private->curregs);
-
-	restore_flags(flags);
-}
-
-/* This is for console output over ttya/ttyb */
-static void SCC_put_char(char ch)
-{
-	struct mac_zschannel *chan = zs_conschan;
-	int loops = 0;
-	unsigned long flags;
-
-	if(!chan)
-		return;
-
-	save_flags(flags); cli();
-	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {
-		loops++;
-		udelay(5);
-	}
-	write_zsdata(chan, ch);
-	restore_flags(flags);
-}
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
-	struct mac_zschannel *chan = zs_kgdbchan;
-
-	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
-		udelay(5);
-	write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
-	struct mac_zschannel *chan = zs_kgdbchan;
-
-	while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-		udelay(5);
-	return read_zsdata(chan);
-}
-
-/*
- * Fair output driver allows a process to speak.
- */
-static void SCC_fair_output(void)
-{
-	int left;		/* Output no more than that */
-	unsigned long flags;
-	struct m68k_async_struct *info = zs_consinfo;
-	char c;
-
-	if (info == 0) return;
-	if (info->xmit_buf == 0) return;
-
-	save_flags(flags);  cli();
-	left = info->xmit_cnt;
-	while (left != 0) {
-		c = info->xmit_buf[info->xmit_tail];
-		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
-		info->xmit_cnt--;
-		restore_flags(flags);
-
-		SCC_put_char(c);
-
-		save_flags(flags);  cli();
-		left = MIN(info->xmit_cnt, left-1);
-	}
-
-	restore_flags(flags);
-	return;
-}
-
-/*
- * zs_console_print is registered for printk.
- */
-static void zs_console_print(const char *p)
-{
-	char c;
-
-	while ((c = *(p++)) != 0) {
-		if (c == '\n')
-			SCC_put_char('\r');
-		SCC_put_char(c);
-	}
-
-	/* Comment this if you want to have a strict interrupt-driven output */
-	SCC_fair_output();
-}
-
-/* FIXME: check with SCC_enab_tx_int!! */
-#if 0
-static void rs_flush_chars(struct tty_struct *tty)
-{
-	struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
-		return;
-
-	if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped ||
-	    !info->xmit_buf)
-		return;
-
-	/* Enable transmitter */
-	save_flags(flags); cli();
-	transmit_chars(info);
-	restore_flags(flags);
-}
-
-static int rs_write(struct tty_struct * tty, int from_user,
-		    const unsigned char *buf, int count)
-{
-	int	c, total = 0;
-	struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->device, "rs_write"))
-		return 0;
-
-	if (!tty || !info->xmit_buf)
-		return 0;
-
-	save_flags(flags);
-	while (1) {
-		cli();		
-		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				   SERIAL_XMIT_SIZE - info->xmit_head));
-		if (c <= 0)
-			break;
-
-		if (from_user) {
-			down(&tmp_buf_sem);
-			memcpy_fromfs(tmp_buf, buf, c);
-			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				       SERIAL_XMIT_SIZE - info->xmit_head));
-			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-			up(&tmp_buf_sem);
-		} else
-			memcpy(info->xmit_buf + info->xmit_head, buf, c);
-		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-		info->xmit_cnt += c;
-		restore_flags(flags);
-		buf += c;
-		count -= c;
-		total += c;
-	}
-	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
-	    && !info->tx_active)
-		transmit_chars(info);
-	restore_flags(flags);
-	return total;
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- * 
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void SCC_throttle(struct m68k_async_struct *info, int status)
-{
-	unsigned long	flags;
-
-	save_flags(flags); 
-	cli();
-
-	if (status) {
-		/*
-		 * Here we want to turn off the RTS line.  On Macintoshes,
-		 * we only get the DTR line, which goes to both DTR and
-		 * RTS on the modem.  RTS doesn't go out to the serial
-		 * port socket.  So you should make sure your modem is
-		 * set to ignore DTR if you're using CRTSCTS.
-		 */
-		info->private->curregs[5] &= ~(DTR | RTS);
-		info->private->pendregs[5] &= ~(DTR | RTS);
-		write_zsreg(info->private->zs_channel, 5, 
-			    info->private->curregs[5]);
-	} else {
-		/* Assert RTS and DTR lines */
-		info->private->curregs[5] |= DTR | RTS;
-		info->private->pendregs[5] |= DTR | RTS;
-		write_zsreg(info->private->zs_channel, 5, 
-			    info->private->curregs[5]);
-	}
-
-	restore_flags(flags);
-
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static void SCC_get_serial_info(struct m68k_async_struct * info,
-			   struct serial_struct * retinfo)
-{
-	retinfo->baud_base = info->baud_base;
-	retinfo->custom_divisor = info->custom_divisor;
-}
-
-/* FIXME: set_serial_info needs check_custom_divisor !!! */
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
- */
-static int SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value)
-{
-	unsigned char status;
-
-	cli();
-	status = read_zsreg(info->private->zs_channel, 0);
-	sti();
-	return status;
-}
-
-static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
-{
-	unsigned char control, status;
-	unsigned int result;
-
-	cli();
-	control = info->private->curregs[5];
-	status = read_zsreg(info->private->zs_channel, 0);
-	sti();
-	result =  ((control & RTS) ? TIOCM_RTS: 0)
-		| ((control & DTR) ? TIOCM_DTR: 0)
-		| ((status  & DCD) ? TIOCM_CAR: 0)
-		| ((status  & CTS) ? 0: TIOCM_CTS);
-	return result;
-}
-
-/* FIXME: zs_setdtr was used in rs_open ... */
-
-static int SCC_set_modem_info(struct m68k_async_struct *info, 
-			      int new_dtr, int new_rts)
-{
-	unsigned int bits;
-
-	bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
-	info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
-	info->private->pendregs[5] = info->private->curregs[5];
-	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
-	sti();
-	return 0;
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void SCC_set_break(struct m68k_async_struct * info, int break_flag)
-{
-	unsigned long	flags;
-
-	save_flags(flags);
-	cli();
-
-	if (break_flag) {
-		info->private->curregs[5] |= SND_BRK;
-		write_zsreg(info->private->zs_channel, 5, 
-			    info->private->curregs[5]);
-	} else {
-		info->private->curregs[5] &= ~SND_BRK;
-		write_zsreg(info->private->zs_channel, 5, 
-			    info->private->curregs[5]);
-	}
-
-	restore_flags(flags);
-}
-
-/* FIXME: these have to be enabled in rs_ioctl !! */
-
-static int SCC_ioctl(struct tty_struct *tty, struct file * file,
-		    struct m68k_async_struct * info, unsigned int cmd, 
-	            unsigned long arg)
-{
-	int error;
-
-	switch (cmd) {
-		case TIOCSERGETLSR: /* Get line status register */
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			else
-			    return SCC_get_lsr_info(info, (unsigned int *) arg);
-
-		case TIOCSERGSTRUCT:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct m68k_async_struct));
-			if (error)
-				return error;
-			copy_to_user((struct m68k_async_struct *) arg,
-				      info, sizeof(struct m68k_async_struct));
-			return 0;
-			
-		default:
-			return -ENOIOCTLCMD;
-		}
-	return 0;
-}
-
-static void SCC_stop_receive (struct m68k_async_struct *info)
-{
-	/* disable Rx */
-	info->private->curregs[3] &= ~RxENABLE;
-	info->private->pendregs[3] = info->private->curregs[3];
-	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
-	/* disable Rx interrupts */
-	info->private->curregs[1] &= ~(0x18);	/* disable any rx ints */
-	info->private->pendregs[1] = info->private->curregs[1];
-	write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]);
-	ZS_CLEARFIFO(info->private->zs_channel);
-}
-
-static int SCC_trans_empty (struct m68k_async_struct *info)
-{
-	return  (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-#ifdef CONFIG_MAC
-
-/*
- *	Mac: use boot_info data; assume 2 channels
- */
- 
-static void probe_sccs(void)
-{
-	int n;
-
-#define ZS_CONTROL	0x50F04000
-#define ZS_DATA		(ZS_CONTROL+4)
-#define ZS_IRQ		5
-#define ZS_MOVE		-2
-#define ZS_DATA_MOVE	4
-#define ZS_CH_A_FIRST	2
-
-	/* last-ditch fixup for NetBSD booter case */
-	if (mac_bi_data.sccbase == 0)
-		mac_bi_data.sccbase = ZS_CONTROL;
-
-	/* testing: fix up broken 24 bit addresses (ClassicII) */
-	if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase)
-		mac_bi_data.sccbase |= 0x50000000;
-		
-	if ( !hwreg_present((void *)mac_bi_data.sccbase))
-	{
-		printk(KERN_WARNING "z8530: Serial devices not accessible. Check serial switch.\n");
-		return;
-	}
-
-	for(n=0;n<2;n++)
-	{
-#if 0
-		zs_channels[n].control = (volatile unsigned char *)
-				ZS_CONTROL+ZS_MOVE*n;
-		zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
-#else
-		zs_channels[n].control = (volatile unsigned char *) /* 2, 0 */
-			(mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
-		zs_channels[n].data = (volatile unsigned char *) /* 6, 4 */
-			(mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
-#endif
-		zs_soft[n].private = &zs_soft_private[n];
-		zs_soft[n].private->zs_channel = &zs_channels[n];
-		zs_soft[n].irq = IRQ4;
-#if 0		
-		if (request_irq(ch->intrs[0], rs_interrupt, 0,
-				"SCC", &zs_soft[n]))
-			panic("macserial: can't get irq %d",
-			      ch->intrs[0]);
-#endif
-		if (n & 1)
-			zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
-		else
-			zs_soft[n].private->zs_chan_a = &zs_channels[n];
-	}
-
-	zs_channels_found=2;
-}
-
-#else
-
-/*
- *	PowerMAC - query the PROM
- */
- 
-static void show_serial_version(void)
-{
-	printk("PowerMac Z8530 serial driver version 1.00\n");
-}
-
-/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
-static void
-probe_sccs()
-{
-	struct device_node *dev, *ch;
-	struct m68k_async_struct **pp;
-	int n;
-
-	n = 0;
-	pp = &zs_chain;
-	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
-		if (n >= NUM_CHANNELS) {
-			printk("Sorry, can't use %s: no more channels\n",
-			       dev->full_name);
-			continue;
-		}
-		for (ch = dev->child; ch != 0; ch = ch->sibling) {
-			if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
-				printk("Can't use %s: %d addrs %d intrs\n",
-				      ch->full_name, ch->n_addrs, ch->n_intrs);
-				continue;
-			}
-			zs_channels[n].control = (volatile unsigned char *)
-				ch->addrs[0].address;
-			zs_channels[n].data = zs_channels[n].control
-				+ ch->addrs[0].size / 2;
-			zs_soft[n].private = &zs_soft_private[n];
-			zs_soft[n].private->zs_channel = &zs_channels[n];
-			zs_soft[n].irq = ch->intrs[0];
-			if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0,
-					"SCC", &zs_soft[n]))
-				panic("macserial: can't get irq %d",
-				      ch->intrs[0]);
-			/* XXX this assumes the prom puts chan A before B */
-			if (n & 1)
-				zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
-			else
-				zs_soft[n].private->zs_chan_a = &zs_channels[n];
-
-			*pp = &zs_soft[n];
-			pp = &zs_soft[n].private->zs_next;
-			++n;
-		}
-	}
-	*pp = 0;
-	zs_channels_found = n;
-}
-
-#endif
-
-extern void register_console(void (*proc)(const char *));
-
-static inline void
-rs_cons_check(struct m68k_async_struct *ss, int channel)
-{
-	int i, o, io;
-	static int consout_registered = 0;
-	static int msg_printed = 0;
-
-	i = o = io = 0;
-
-	/* Is this one of the serial console lines? */
-	if ((zs_cons_chanout != channel) &&
-	    (zs_cons_chanin != channel))
-		return;
-	zs_conschan = ss->private->zs_channel;
-	zs_consinfo = ss;
-
-	/* Register the console output putchar, if necessary */
-	if (zs_cons_chanout == channel) {
-		o = 1;
-		/* double whee.. */
-		if (!consout_registered) {
-			register_console(zs_console_print);
-			consout_registered = 1;
-		}
-	}
-
-	if (zs_cons_chanin == channel) {
-		i = 1;
-	}
-	if (o && i)
-		io = 1;
-	if (ss->private->zs_baud != 9600)
-		panic("Console baud rate weirdness");
-
-	/* Set flag variable for this port so that it cannot be
-	 * opened for other uses by accident.
-	 */
-	ss->private->is_cons = 1;
-
-	if (io) {
-		if(!msg_printed) {
-			printk("zs%d: console I/O\n", ((channel>>1)&1));
-			msg_printed = 1;
-		}
-	} else {
-		printk("zs%d: console %s\n", ((channel>>1)&1),
-		       (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
-	}
-
-	/* FIXME : register interrupt here??? */
-}
-
-volatile int test_done;
-
-/* rs_init inits the driver */
-int mac_SCC_init(void)
-{
-	int channel, line, nr = 0;
-	unsigned long flags;
-	struct serial_struct req;
-
-	printk("Mac68K Z8530 serial driver version 1.01\n");
-
-	/* SCC present at all? */
-	if (!MACH_IS_MAC)
-		return( -ENODEV );
-
-	if (zs_chain == 0)
-		probe_sccs();
-
-	save_flags(flags);
-	cli();
-
-	/* 
-	 * FIXME: init of rs_table entry and register_serial now done,
-	 * but possible clash of zs_soft[channel] and rs_table[channel]!!
-	 * zs_soft initialized in probe_sccs(), some settings copied to
-	 * info = &rs_table[channel], which is used by the mid-level code.
-	 * The info->private part is shared among both!
-	 */
-
-	for (channel = 0; channel < zs_channels_found; ++channel) {
-		req.line = channel;
-		req.type = SER_SCC_MAC;
-		req.port = (int) zs_soft[channel].private->zs_channel->control;
-
-		if ((line = register_serial( &req )) >= 0) {
-			SCC_init_port( &rs_table[line], req.type, line );
-			++nr;
-		}
-		else
-			printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line );
-	}
-
-	restore_flags(flags);
-
-	return( nr > 0 ? 0 : -ENODEV );
-}
-
-/* Hooks for running a serial console.  con_init() calls this if the
- * console is being run over one of the serial ports.
- * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored.
- */
-void
-rs_cons_hook(int chip, int out, int channel)
-{
-	if (zs_chain == 0)
-		probe_sccs();
-	zs_soft[channel].private->clk_divisor = 16;
-	zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]);
-	rs_cons_check(&zs_soft[channel], channel);
-	if (out)
-		zs_cons_chanout = channel;
-	else
-		zs_cons_chanin = channel;
-
-	/* FIXME : register interrupt here??? */
-}
-
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line.  The 'tty_num' argument is 0 for /dev/ttyS0 and 1
- * for /dev/ttyS1 which is determined in setup_arch() from the
- * boot command line flags.
- */
-void
-rs_kgdb_hook(int tty_num)
-{
-	if (zs_chain == 0)
-		probe_sccs();
-	zs_kgdbchan = zs_soft[tty_num].private->zs_channel;
-	zs_soft[tty_num].private->clk_divisor = 16;
-	zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]);
-	zs_soft[tty_num].private->kgdb_channel = 1;     /* This runs kgdb */
-	zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */
-	/* Turn on transmitter/receiver at 8-bits/char */
-	kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
-	ZS_CLEARERR(zs_kgdbchan);
-	ZS_CLEARFIFO(zs_kgdbchan);
-
-	/* FIXME : register interrupt here??? */
-}
-
diff -u --recursive --new-file v2.3.44/linux/drivers/char/mac_SCC.h linux/drivers/char/mac_SCC.h
--- v2.3.44/linux/drivers/char/mac_SCC.h	Sat Jun 13 13:44:30 1998
+++ linux/drivers/char/mac_SCC.h	Wed Dec 31 16:00:00 1969
@@ -1,321 +0,0 @@
-/*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _MAC_SCC_H
-#define _MAC_SCC_H
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output.  65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF	0
-#define ZILOG_CLOSING_WAIT_NONE	65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
-				   on the callout port */
-#define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK	0x0030
-#define ZILOG_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST	0x0030  /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS	0x0FFF	/* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430	/* Legal flags that non-privileged
-				 * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-/* MSch: gone to <asm/serial.h> */
-
-#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
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define	FLAG	0x7e
-
-/* Write Register 0 */
-#define	R0	0		/* Register selects */
-#define	R1	1
-#define	R2	2
-#define	R3	3
-#define	R4	4
-#define	R5	5
-#define	R6	6
-#define	R7	7
-#define	R8	8
-#define	R9	9
-#define	R10	10
-#define	R11	11
-#define	R12	12
-#define	R13	13
-#define	R14	14
-#define	R15	15
-
-#define	NULLCODE	0	/* Null Code */
-#define	POINT_HIGH	0x8	/* Select upper half of registers */
-#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
-#define	SEND_ABORT	0x18	/* HDLC Abort */
-#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
-#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
-#define	ERR_RES		0x30	/* Error Reset */
-#define	RES_H_IUS	0x38	/* Reset highest IUS */
-
-#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
-#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
-#define	RES_EOM_L	0xC0	/* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
-#define	TxINT_ENAB	0x2	/* Tx Int Enable */
-#define	PAR_SPEC	0x4	/* Parity is special condition */
-
-#define	RxINT_DISAB	0	/* Rx Int Disable */
-#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
-#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
-#define	INT_ERR_Rx	0x18	/* Int on error only */
-
-#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
-#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
-#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define	RxENABLE	0x1	/* Rx Enable */
-#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
-#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
-#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
-#define	ENT_HM		0x10	/* Enter Hunt Mode */
-#define	AUTO_ENAB	0x20	/* Auto Enables */
-#define	Rx5		0x0	/* Rx 5 Bits/Character */
-#define	Rx7		0x40	/* Rx 7 Bits/Character */
-#define	Rx6		0x80	/* Rx 6 Bits/Character */
-#define	Rx8		0xc0	/* Rx 8 Bits/Character */
-#define RxNBITS_MASK	0xc0
-
-/* Write Register 4 */
-
-#define	PAR_ENA		0x1	/* Parity Enable */
-#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
-
-#define	SYNC_ENAB	0	/* Sync Modes Enable */
-#define	SB1		0x4	/* 1 stop bit/char */
-#define	SB15		0x8	/* 1.5 stop bits/char */
-#define	SB2		0xc	/* 2 stop bits/char */
-#define SB_MASK		0xc
-
-#define	MONSYNC		0	/* 8 Bit Sync character */
-#define	BISYNC		0x10	/* 16 bit sync character */
-#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
-#define	EXTSYNC		0x30	/* External Sync Mode */
-
-#define	X1CLK		0x0	/* x1 clock mode */
-#define	X16CLK		0x40	/* x16 clock mode */
-#define	X32CLK		0x80	/* x32 clock mode */
-#define	X64CLK		0xC0	/* x64 clock mode */
-#define XCLK_MASK	0xC0
-
-/* Write Register 5 */
-
-#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
-#define	RTS		0x2	/* RTS */
-#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
-#define	TxENAB		0x8	/* Tx Enable */
-#define	SND_BRK		0x10	/* Send Break */
-#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
-#define	Tx7		0x20	/* Tx 7 bits/character */
-#define	Tx6		0x40	/* Tx 6 bits/character */
-#define	Tx8		0x60	/* Tx 8 bits/character */
-#define TxNBITS_MASK	0x60
-#define	DTR		0x80	/* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define	VIS	1	/* Vector Includes Status */
-#define	NV	2	/* No Vector */
-#define	DLC	4	/* Disable Lower Chain */
-#define	MIE	8	/* Master Interrupt Enable */
-#define	STATHI	0x10	/* Status high */
-#define	NORESET	0	/* No reset on write to R9 */
-#define	CHRB	0x40	/* Reset channel B */
-#define	CHRA	0x80	/* Reset channel A */
-#define	FHWRES	0xc0	/* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define	BIT6	1	/* 6 bit/8bit sync */
-#define	LOOPMODE 2	/* SDLC Loop mode */
-#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
-#define	MARKIDLE 8	/* Mark/flag on idle */
-#define	GAOP	0x10	/* Go active on poll */
-#define	NRZ	0	/* NRZ mode */
-#define	NRZI	0x20	/* NRZI mode */
-#define	FM1	0x40	/* FM1 (transition = 1) */
-#define	FM0	0x60	/* FM0 (transition = 0) */
-#define	CRCPS	0x80	/* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define	TRxCXT	0	/* TRxC = Xtal output */
-#define	TRxCTC	1	/* TRxC = Transmit clock */
-#define	TRxCBR	2	/* TRxC = BR Generator Output */
-#define	TRxCDP	3	/* TRxC = DPLL output */
-#define	TRxCOI	4	/* TRxC O/I */
-#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
-#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
-#define	TCBR	0x10	/* Transmit clock = BR Generator output */
-#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
-#define	RCRTxCP	0	/* Receive clock = RTxC pin */
-#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
-#define	RCBR	0x40	/* Receive clock = BR Generator output */
-#define	RCDPLL	0x60	/* Receive clock = DPLL output */
-#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define	BRENABL	1	/* Baud rate generator enable */
-#define	BRSRC	2	/* Baud rate generator source */
-#define	DTRREQ	4	/* DTR/Request function */
-#define	AUTOECHO 8	/* Auto Echo */
-#define	LOOPBAK	0x10	/* Local loopback */
-#define	SEARCH	0x20	/* Enter search mode */
-#define	RMC	0x40	/* Reset missing clock */
-#define	DISDPLL	0x60	/* Disable DPLL */
-#define	SSBR	0x80	/* Set DPLL source = BR generator */
-#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
-#define	SFMM	0xc0	/* Set FM mode */
-#define	SNRZI	0xe0	/* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define	ZCIE	2	/* Zero count IE */
-#define	DCDIE	8	/* DCD IE */
-#define	SYNCIE	0x10	/* Sync/hunt IE */
-#define	CTSIE	0x20	/* CTS IE */
-#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
-#define	BRKIE	0x80	/* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define	Rx_CH_AV	0x1	/* Rx Character Available */
-#define	ZCOUNT		0x2	/* Zero count */
-#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
-#define	DCD		0x8	/* DCD */
-#define	SYNC_HUNT	0x10	/* Sync/hunt */
-#define	CTS		0x20	/* CTS */
-#define	TxEOM		0x40	/* Tx underrun */
-#define	BRK_ABRT	0x80	/* Break/Abort */
-
-/* Read Register 1 */
-#define	ALL_SNT		0x1	/* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define	RES3		0x8	/* 0/3 */
-#define	RES4		0x4	/* 0/4 */
-#define	RES5		0xc	/* 0/5 */
-#define	RES6		0x2	/* 0/6 */
-#define	RES7		0xa	/* 0/7 */
-#define	RES8		0x6	/* 0/8 */
-#define	RES18		0xe	/* 1/8 */
-#define	RES28		0x0	/* 2/8 */
-/* Special Rx Condition Interrupts */
-#define	PAR_ERR		0x10	/* Parity error */
-#define	Rx_OVR		0x20	/* Rx Overrun Error */
-#define	FRM_ERR		0x40	/* CRC/Framing Error */
-#define	END_FR		0x80	/* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
-#define	CHBTxIP	0x2		/* Channel B Tx IP */
-#define	CHBRxIP	0x4		/* Channel B Rx IP */
-#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
-#define	CHATxIP	0x10		/* Channel A Tx IP */
-#define	CHARxIP	0x20		/* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define	ONLOOP	2		/* On loop */
-#define	LOOPSEND 0x10		/* Loop sending */
-#define	CLK2MIS	0x40		/* Two clocks missing */
-#define	CLK1MIS	0x80		/* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
-				     garbage = read_zsdata(channel); \
-				     garbage = read_zsdata(channel); \
-				     garbage = read_zsdata(channel); \
-				} while(0)
-
-#endif /* !(_MAC_SCC_H) */
diff -u --recursive --new-file v2.3.44/linux/drivers/char/nvram.c linux/drivers/char/nvram.c
--- v2.3.44/linux/drivers/char/nvram.c	Thu Feb 10 17:11:08 2000
+++ linux/drivers/char/nvram.c	Sun Feb 13 10:47:01 2000
@@ -38,7 +38,7 @@
 /* select machine configuration */
 #if defined(CONFIG_ATARI)
 #define MACH ATARI
-#elif defined(__i386__) /* and others?? */
+#elif defined(__i386__) || defined(__arm__) /* and others?? */
 #define MACH PC
 #else
 #error Cannot build nvram driver for this machine configuration.
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- v2.3.44/linux/drivers/macintosh/Makefile	Thu Feb 10 17:11:09 2000
+++ linux/drivers/macintosh/Makefile	Sun Feb 13 11:21:42 2000
@@ -68,6 +68,10 @@
   L_OBJS += via-pmu.o
 endif
 
+ifdef CONFIG_ADB_PMU68K
+  L_OBJS += via-pmu68k.o
+endif
+
 ifdef CONFIG_ADB_MACIO
   L_OBJS += macio-adb.o
 endif
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/adb-iop.c linux/drivers/macintosh/adb-iop.c
--- v2.3.44/linux/drivers/macintosh/adb-iop.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/adb-iop.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,284 @@
+/*
+ * I/O Processor (IOP) ADB Driver
+ * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
+ * Based on via-cuda.c by Paul Mackerras.
+ *
+ * 1999-07-01 (jmt) - First implementation for new driver architecture.
+ *
+ * 1999-07-31 (jmt) - First working version.
+ *
+ * TODO:
+ *
+ * o Implement SRQ handling.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/bootinfo.h> 
+#include <asm/macintosh.h> 
+#include <asm/macints.h> 
+#include <asm/mac_iop.h>
+#include <asm/mac_oss.h>
+#include <asm/adb_iop.h>
+
+#include <linux/adb.h> 
+
+/*#define DEBUG_ADB_IOP*/
+
+extern void iop_ism_irq(int, void *, struct pt_regs *);
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+#if 0
+static unsigned char reply_buff[16];
+static unsigned char *reply_ptr;
+#endif
+
+static enum adb_iop_state {
+    idle,
+    sending,
+    awaiting_reply
+} adb_iop_state;
+
+static void adb_iop_start(void);
+static int adb_iop_probe(void);
+static int adb_iop_init(void);
+static int adb_iop_send_request(struct adb_request *, int);
+static int adb_iop_write(struct adb_request *);
+static int adb_iop_autopoll(int);
+static void adb_iop_poll(void);
+static int adb_iop_reset_bus(void);
+
+struct adb_driver adb_iop_driver = {
+	"ISM IOP",
+	adb_iop_probe,
+	adb_iop_init,
+	adb_iop_send_request,
+	adb_iop_autopoll,
+	adb_iop_poll,
+	adb_iop_reset_bus
+};
+
+static void adb_iop_end_req(struct adb_request *req, int state)
+{
+	req->complete = 1;
+	current_req = req->next;
+	if (req->done) (*req->done)(req);
+	adb_iop_state = state;
+}
+
+/*
+ * Completion routine for ADB commands sent to the IOP.
+ *
+ * This will be called when a packet has been successfully sent.
+ */
+
+static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
+{
+	struct adb_request *req;
+	uint flags;
+
+	save_flags(flags);
+	cli();
+
+	req = current_req;
+	if ((adb_iop_state == sending) && req && req->reply_expected) {
+		adb_iop_state = awaiting_reply;
+	}
+
+	restore_flags(flags);
+}
+
+/*
+ * Listen for ADB messages from the IOP.
+ *
+ * This will be called when unsolicited messages (usually replies to TALK
+ * commands or autopoll packets) are received.
+ */
+
+static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
+{
+	struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
+	struct adb_request *req;
+	uint flags;
+
+	save_flags(flags);
+	cli();
+
+	req = current_req;
+
+#ifdef DEBUG_ADB_IOP
+	printk("adb_iop_listen: rcvd packet, %d bytes: %02X %02X",
+		(uint) amsg->count + 2, (uint) amsg->flags, (uint) amsg->cmd);
+	i = 0;
+	while (i < amsg->count) {
+		printk(" %02X", (uint) amsg->data[i++]);
+	}
+	printk("\n");
+#endif
+
+	/* Handle a timeout. Timeout packets seem to occur even after */
+	/* we've gotten a valid reply to a TALK, so I'm assuming that */
+	/* a "timeout" is actually more like an "end-of-data" signal. */
+	/* We need to send back a timeout packet to the IOP to shut   */
+	/* it up, plus complete the current request, if any.          */
+
+	if (amsg->flags & ADB_IOP_TIMEOUT) {
+		msg->reply[0] = ADB_IOP_TIMEOUT | ADB_IOP_AUTOPOLL;
+		msg->reply[1] = 0;
+		msg->reply[2] = 0;
+		if (req && (adb_iop_state != idle)) {
+			adb_iop_end_req(req, idle);
+		}
+	} else {
+		/* TODO: is it possible for more tha one chunk of data  */
+		/*       to arrive before the timeout? If so we need to */
+		/*       use reply_ptr here like the other drivers do.  */
+		if ((adb_iop_state == awaiting_reply) &&
+		    (amsg->flags & ADB_IOP_EXPLICIT)) {
+			req->reply_len = amsg->count + 1;
+			memcpy(req->reply, &amsg->cmd, req->reply_len);
+		} else {
+			adb_input(&amsg->cmd, amsg->count + 1, regs,
+				  amsg->flags & ADB_IOP_AUTOPOLL);
+		}
+		memcpy(msg->reply, msg->message, IOP_MSG_LEN);
+	}
+	iop_complete_message(msg);
+	restore_flags(flags);
+}
+
+/*
+ * Start sending an ADB packet, IOP style
+ *
+ * There isn't much to do other than hand the packet over to the IOP
+ * after encapsulating it in an adb_iopmsg.
+ */
+
+static void adb_iop_start(void)
+{
+	unsigned long flags;
+	struct adb_request *req;
+	struct adb_iopmsg amsg;
+
+	/* get the packet to send */
+	req = current_req;
+	if (!req) return;
+
+	save_flags(flags);
+	cli();
+
+#ifdef DEBUG_ADB_IOP
+	printk("adb_iop_start: sending packet, %d bytes:", req->nbytes);
+	for (i = 0 ; i < req->nbytes ; i++)
+		printk(" %02X", (uint) req->data[i]);
+	printk("\n");
+#endif
+
+	/* The IOP takes MacII-style packets, so */
+	/* strip the initial ADB_PACKET byte.    */
+
+	amsg.flags = ADB_IOP_EXPLICIT;
+	amsg.count = req->nbytes - 2;
+
+	/* amsg.data immediately follows amsg.cmd, effectively making */
+	/* amsg.cmd a pointer to the beginning of a full ADB packet.  */
+	memcpy(&amsg.cmd, req->data + 1, req->nbytes - 1);
+
+	req->sent = 1;
+	adb_iop_state = sending;
+	restore_flags(flags);
+
+	/* Now send it. The IOP manager will call adb_iop_complete */
+	/* when the packet has been sent.                          */
+
+	iop_send_message(ADB_IOP, ADB_CHAN, req,
+			 sizeof(amsg), (__u8 *) &amsg, adb_iop_complete);
+}
+
+int adb_iop_probe(void)
+{
+	if (!iop_ism_present) return -ENODEV;
+	return 0;
+}
+
+int adb_iop_init(void)
+{
+	printk("adb: IOP ISM driver v0.4 for Unified ADB.\n");
+	iop_listen(ADB_IOP, ADB_CHAN, adb_iop_listen, "ADB");
+	return 0;
+}
+
+int adb_iop_send_request(struct adb_request *req, int sync)
+{
+	int err;
+
+	err = adb_iop_write(req);
+	if (err) return err;
+
+	if (sync) {
+		while (!req->complete) adb_iop_poll();
+	}
+	return 0;
+}
+
+static int adb_iop_write(struct adb_request *req)
+{
+	unsigned long flags;
+
+	if ((req->nbytes < 2) || (req->data[0] != ADB_PACKET)) {
+		req->complete = 1;
+		return -EINVAL;
+	}
+
+	save_flags(flags);
+	cli();
+
+	req->next = 0;
+	req->sent = 0;
+	req->complete = 0;
+	req->reply_len = 0;
+
+	if (current_req != 0) {
+		last_req->next = req;
+		last_req = req;
+	} else {
+		current_req = req;
+		last_req = req;
+	}
+
+	restore_flags(flags);
+	if (adb_iop_state == idle) adb_iop_start();
+	return 0;
+}
+
+int adb_iop_autopoll(int devs)
+{
+	/* TODO: how do we enable/disable autopoll? */
+	return 0;
+}
+
+void adb_iop_poll(void)
+{
+	if (adb_iop_state == idle) adb_iop_start();
+	iop_ism_irq(0, (void *) ADB_IOP, NULL);
+}
+
+int adb_iop_reset_bus(void)
+{
+	struct adb_request req;
+
+	req.reply_expected = 0;
+	req.nbytes = 2;
+	req.data[0] = ADB_PACKET;
+	req.data[1] = 0; /* RESET */
+	adb_iop_write(&req);
+	while (!req.complete) adb_iop_poll();
+	return 0;
+}
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.3.44/linux/drivers/macintosh/mac_keyb.c	Thu Feb 10 17:11:09 2000
+++ linux/drivers/macintosh/mac_keyb.c	Sun Feb 13 10:47:01 2000
@@ -391,16 +391,17 @@
 		 case 0x39:
 			handle_scancode(0x39, 1);
 			handle_scancode(0x39, 0);
-		 	mark_bh(KEYBOARD_BH);
+		 	tasklet_schedule(&keyboard_tasklet);
 		 	return;
 		 case 0x47:
 		 /*case 0xc7:*/
-		 	mark_bh(KEYBOARD_BH);
+		 	tasklet_schedule(&keyboard_tasklet);
 		 	break;
 		 }
 	}
 
 	handle_scancode(keycode, !up_flag);
+	tasklet_schedule(&keyboard_tasklet);
 }
 
 static void
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.44/linux/drivers/macintosh/macserial.c	Thu Feb 10 17:11:09 2000
+++ linux/drivers/macintosh/macserial.c	Sun Feb 13 10:47:01 2000
@@ -2796,7 +2796,6 @@
 void __init serial_console_init(void)
 {
 	register_console(&sercons);
-	return kmem_start;
 }
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
 
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/via-macii.c linux/drivers/macintosh/via-macii.c
--- v2.3.44/linux/drivers/macintosh/via-macii.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/via-macii.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,679 @@
+/*
+ * Device driver for the via ADB on (many) Mac II-class machines
+ *
+ * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox
+ * Also derived from code Copyright (C) 1996 Paul Mackerras.
+ *
+ * With various updates provided over the years by Michael Schmitz,
+ * Guideo Koerber and others.
+ *
+ * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org)
+ *
+ * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
+ */
+ 
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/adb.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/init.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS		0x200		/* skip between registers */
+#define B		0		/* B-side data */
+#define A		RS		/* A-side data */
+#define DIRB		(2*RS)		/* B-side direction (1=output) */
+#define DIRA		(3*RS)		/* A-side direction (1=output) */
+#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
+#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
+#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
+#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */
+#define SR		(10*RS)		/* Shift register */
+#define ACR		(11*RS)		/* Auxiliary control register */
+#define PCR		(12*RS)		/* Peripheral control register */
+#define IFR		(13*RS)		/* Interrupt flag register */
+#define IER		(14*RS)		/* Interrupt enable register */
+#define ANH		(15*RS)		/* A-side data, no handshake */
+
+/* Bits in B data register: all active low */
+#define TREQ		0x08		/* Transfer request (input) */
+#define TACK		0x10		/* Transfer acknowledge (output) */
+#define TIP		0x20		/* Transfer in progress (output) */
+#define ST_MASK		0x30		/* mask for selecting ADB state bits */
+
+/* Bits in ACR */
+#define SR_CTRL		0x1c		/* Shift register control bits */
+#define SR_EXT		0x0c		/* Shift on external clock */
+#define SR_OUT		0x10		/* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET		0x80		/* set bits in IER */
+#define IER_CLR		0		/* clear bits in IER */
+#define SR_INT		0x04		/* Shift register full/empty */
+#define SR_DATA		0x08		/* Shift register data */
+#define SR_CLOCK	0x10		/* Shift register clock */
+
+/* ADB transaction states according to GMHW */
+#define ST_CMD		0x00		/* ADB state: command byte */
+#define ST_EVEN		0x10		/* ADB state: even data byte */
+#define ST_ODD		0x20		/* ADB state: odd data byte */
+#define ST_IDLE		0x30		/* ADB state: idle, nothing to send */
+
+static int  macii_init_via(void);
+static void macii_start(void);
+static void macii_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void macii_retransmit(int);
+static void macii_queue_poll(void);
+
+static int macii_probe(void);
+static int macii_init(void);
+static int macii_send_request(struct adb_request *req, int sync);
+static int macii_write(struct adb_request *req);
+static int macii_autopoll(int devs);
+static void macii_poll(void);
+static int macii_reset_bus(void);
+
+struct adb_driver via_macii_driver = {
+	"Mac II",
+	macii_probe,
+	macii_init,
+	macii_send_request,
+	macii_autopoll,
+	macii_poll,
+	macii_reset_bus
+};
+
+static enum macii_state {
+	idle,
+	sent_first_byte,
+	sending,
+	reading,
+	read_done,
+	awaiting_reply
+} macii_state;
+
+static int need_poll    = 0;
+static int command_byte = 0;
+static int last_reply   = 0;
+static int last_active  = 0;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static struct adb_request *retry_req;
+static unsigned char reply_buf[16];
+static unsigned char *reply_ptr;
+static int reply_len;
+static int reading_reply;
+static int data_index;
+static int first_byte;
+static int prefix_len;
+static int status = ST_IDLE|TREQ;
+static int last_status;
+static int driver_running = 0;
+
+/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */
+extern int console_loglevel;
+
+/* Check for MacII style ADB */
+static int macii_probe(void)
+{
+	if (macintosh_config->adb_type != MAC_ADB_II) return -ENODEV;
+
+	via = via1;
+
+	printk("adb: Mac II ADB Driver v0.4 for Unified ADB\n");
+	return 0;
+}
+
+/* Initialize the driver */
+int macii_init(void)
+{
+	unsigned long flags;
+	int err;
+	
+	save_flags(flags);
+	cli();
+	
+	err = macii_init_via();
+	if (err) return err;
+
+	err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
+		    macii_interrupt);
+	if (err) return err;
+
+	macii_state = idle;
+	restore_flags(flags);	
+	return 0;
+}
+
+/* initialize the hardware */	
+static int macii_init_via(void)
+{
+	unsigned char x;
+
+	/* Set the lines up. We want TREQ as input TACK|TIP as output */
+	via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
+
+	/* Set up state: idle */
+	via[B] |= ST_IDLE;
+	last_status = via[B] & (ST_MASK|TREQ);
+
+	/* Shift register on input */
+	via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
+
+	/* Wipe any pending data and int */
+	x = via[SR];
+
+	return 0;
+}
+
+/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */
+static void macii_queue_poll(void)
+{
+	static int device = 0;
+	static int in_poll=0;
+	static struct adb_request req;
+	unsigned long flags;
+
+	if (in_poll) printk("macii_queue_poll: double poll!\n");
+
+	in_poll++;
+	if (++device > 15) device = 1;
+
+	adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
+		    ADB_READREG(device, 0));
+
+	save_flags(flags);
+	cli();
+
+	req.next = current_req;
+	current_req = &req;
+
+	restore_flags(flags);
+	macii_start();
+	in_poll--;
+}
+
+/* Send an ADB retransmit (Talk, appended to the request queue) */
+static void macii_retransmit(int device)
+{
+	static int in_retransmit = 0;
+	static struct adb_request rt;
+	unsigned long flags;
+
+	if (in_retransmit) printk("macii_retransmit: double retransmit!\n");
+
+	in_retransmit++;
+
+	adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
+		    ADB_READREG(device, 0));
+
+	save_flags(flags);
+	cli();
+
+	if (current_req != NULL) {
+		last_req->next = &rt;
+		last_req = &rt;
+	} else {
+		current_req = &rt;
+		last_req = &rt;
+	}
+
+	if (macii_state == idle) macii_start();
+
+	restore_flags(flags);
+	in_retransmit--;
+}
+
+/* Send an ADB request; if sync, poll out the reply 'till it's done */
+static int macii_send_request(struct adb_request *req, int sync)
+{
+	int i;
+
+	i = macii_write(req);
+	if (i) return i;
+
+	if (sync) {
+		while (!req->complete) macii_poll();
+	}
+	return 0;
+}
+
+/* Send an ADB request */
+static int macii_write(struct adb_request *req)
+{
+	unsigned long flags;
+
+	if (req->nbytes < 2 || req->data[0] != ADB_PACKET) {
+		req->complete = 1;
+		return -EINVAL;
+	}
+
+	req->next = 0;
+	req->sent = 0;
+	req->complete = 0;
+	req->reply_len = 0;
+
+	save_flags(flags); cli();
+
+	if (current_req != NULL) {
+		last_req->next = req;
+		last_req = req;
+	} else {
+		current_req = req;
+		last_req = req;
+		if (macii_state == idle) macii_start();
+	}
+
+	restore_flags(flags);
+	return 0;
+}
+
+/* Start auto-polling */
+static int macii_autopoll(int devs)
+{
+	/* Just ping a random default address */
+	if (!(current_req || retry_req))
+		macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3);
+	return 0;
+}
+
+/* Prod the chip without interrupts */
+static void macii_poll(void)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (via[IFR] & SR_INT) macii_interrupt(0, 0, 0);
+	restore_flags(flags);
+}
+
+/* Reset the bus */
+static int macii_reset_bus(void)
+{
+	static struct adb_request req;
+	
+	/* Command = 0, Address = ignored */
+	adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
+
+	return 0;
+}
+
+/* Start sending ADB packet */
+static void macii_start(void)
+{
+	unsigned long flags;
+	struct adb_request *req;
+
+	req = current_req;
+	if (!req) return;
+
+	/* assert macii_state == idle */
+	if (macii_state != idle) {
+		printk("macii_start: called while driver busy (%p %x %x)!\n",
+			req, macii_state, (uint) via1[B] & (ST_MASK|TREQ));
+		return;
+	}
+
+	save_flags(flags); cli();
+	
+	/* 
+	 * IRQ signaled ?? (means ADB controller wants to send, or might 
+	 * be end of packet if we were reading)
+	 */
+	if ((via[B] & TREQ) == 0) {
+		/*
+		 *	FIXME - we need to restart this on a timer
+		 *	or a collision at boot hangs us.
+		 *	Never set macii_state to idle here, or macii_start 
+		 *	won't be called again from send_request!
+		 *	(need to re-check other cases ...)
+		 */
+		/*
+		 * if the interrupt handler set the need_poll
+		 * flag, it's hopefully a SRQ poll or re-Talk
+		 * so we try to send here anyway
+		 */
+		if (!need_poll) {
+			if (console_loglevel == 10)
+				printk("macii_start: device busy - retry %p state %d status %x!\n", 
+					req, macii_state,
+					(uint) via[B] & (ST_MASK|TREQ));
+			retry_req = req;
+			/* set ADB status here ? */
+			restore_flags(flags);
+			return;
+		} else {
+			need_poll = 0;
+		}
+	}
+	/*
+	 * Another retry pending? (sanity check)
+	 */
+	if (retry_req) {
+		retry_req = NULL;
+	}
+
+	/* Now send it. Be careful though, that first byte of the request */
+	/* is actually ADB_PACKET; the real data begins at index 1!	  */
+
+	/* store command byte */
+	command_byte = req->data[1];
+	/* Output mode */
+	via[ACR] |= SR_OUT;
+	/* Load data */
+	via[SR] = req->data[1];
+	/* set ADB state to 'command' */
+	via[B] = (via[B] & ~ST_MASK) | ST_CMD;
+
+	macii_state = sent_first_byte;
+	data_index = 2;
+
+	restore_flags(flags);
+}
+
+/*
+ * The notorious ADB interrupt handler - does all of the protocol handling, 
+ * except for starting new send operations. Relies heavily on the ADB 
+ * controller sending and receiving data, thereby generating SR interrupts
+ * for us. This means there has to be always activity on the ADB bus, otherwise
+ * the whole process dies and has to be re-kicked by sending TALK requests ...
+ * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
+ * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
+ * a good choice; either on timeout or on a timer interrupt).
+ *
+ * The basic ADB state machine was left unchanged from the original MacII code
+ * by Alan Cox, which was based on the CUDA driver for PowerMac. 
+ * The syntax of the ADB status lines seems to be totally different on MacII, 
+ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
+ * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start 
+ * and end of a receive packet are signaled by asserting /IRQ on the interrupt
+ * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on 
+ * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the 
+ * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB 
+ * protocol with a logic analyzer!!)
+ *
+ * Note: As of 21/10/97, the MacII ADB part works including timeout detection
+ * and retransmit (Talk to the last active device).
+ */
+void macii_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+	int x, adbdir;
+	unsigned long flags;
+	struct adb_request *req;
+
+	last_status = status;
+
+	/* prevent races due to SCSI enabling ints */
+	save_flags(flags); cli();
+
+	if (driver_running) {
+		restore_flags(flags);
+		return;
+	}
+
+	driver_running = 1;
+	
+	status = via[B] & (ST_MASK|TREQ);
+	adbdir = via[ACR] & SR_OUT;
+
+	switch (macii_state) {
+		case idle:
+			x = via[SR];
+			first_byte = x;
+			/* set ADB state = even for first data byte */
+			via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+
+			reply_buf[0] = first_byte; /* was command_byte?? */
+			reply_ptr = reply_buf + 1;
+			reply_len = 1;
+			prefix_len = 1;
+			reading_reply = 0;
+
+			macii_state = reading;
+			break;
+
+		case awaiting_reply:
+			/* handshake etc. for II ?? */
+			x = via[SR];
+			first_byte = x;
+			/* set ADB state = even for first data byte */
+			via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+
+			current_req->reply[0] = first_byte;
+			reply_ptr = current_req->reply + 1;
+			reply_len = 1;
+			prefix_len = 1;
+			reading_reply = 1;
+
+			macii_state = reading;			
+			break;
+
+		case sent_first_byte:
+			req = current_req;
+			/* maybe we're already done (Talk, or Poll)? */
+			if (data_index >= req->nbytes) {
+				/* reset to shift in */
+				/* If it's a Listen command and we're done, someone's doing weird stuff. */
+				if (((command_byte & 0x0C) == 0x08)
+				    && (console_loglevel == 10))
+					printk("macii_interrupt: listen command with no data: %x!\n", 
+						command_byte);
+				/* reset to shift in */
+				via[ACR] &= ~SR_OUT;
+				x = via[SR];
+				/* set ADB state idle - might get SRQ */
+				via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+
+				req->sent = 1;
+
+				if (req->reply_expected) {
+					macii_state = awaiting_reply;
+				} else {
+					req->complete = 1;
+					current_req = req->next;
+					if (req->done) (*req->done)(req);
+					macii_state = idle;
+					if (current_req || retry_req)
+						macii_start();
+					else
+						macii_retransmit((command_byte & 0xF0) >> 4);
+				}
+			} else {
+				/* SR already set to shift out; send byte */
+				via[SR] = current_req->data[data_index++];
+				/* set state to ST_EVEN (first byte was: ST_CMD) */
+				via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+				macii_state = sending;
+			}
+			break;
+
+		case sending:
+			req = current_req;
+			if (data_index >= req->nbytes) {
+				/* reset to shift in */
+				via[ACR] &= ~SR_OUT;
+				x = via[SR];
+				/* set ADB state idle - might get SRQ */
+				via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+
+				req->sent = 1;
+
+				if (req->reply_expected) {
+					macii_state = awaiting_reply;
+				} else {
+					req->complete = 1;
+					current_req = req->next;
+					if (req->done) (*req->done)(req);
+					macii_state = idle;
+					if (current_req || retry_req)
+						macii_start();
+					else
+						macii_retransmit((command_byte & 0xF0) >> 4);
+				}
+			} else {
+				via[SR] = req->data[data_index++];
+
+				/* invert state bits, toggle ODD/EVEN */
+				via[B] ^= ST_MASK;
+			}
+			break;
+
+		case reading:
+
+			/* timeout / SRQ handling for II hw */
+			if( (first_byte == 0xFF && (reply_len-prefix_len)==2 
+			     && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || 
+			    ((reply_len-prefix_len)==3 
+			     && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
+			{
+				/*
+				 * possible timeout (in fact, most probably a 
+				 * timeout, since SRQ can't be signaled without
+				 * transfer on the bus).
+				 * The last three bytes seen were FF, together 
+				 * with the starting byte (in case we started
+				 * on 'idle' or 'awaiting_reply') this probably
+				 * makes four. So this is mostl likely #5!
+				 * The timeout signal is a pattern 1 0 1 0 0..
+				 * on /INT, meaning we missed it :-(
+				 */
+				x = via[SR];
+				if (x != 0xFF) printk("macii_interrupt: mistaken timeout/SRQ!\n");
+
+				if ((status & TREQ) == (last_status & TREQ)) {
+					/* Not a timeout. Unsolicited SRQ? weird. */
+					/* Terminate the SRQ packet and poll */
+					need_poll = 1;
+				}
+				/* There's no packet to get, so reply is blank */
+				via[B] ^= ST_MASK;
+				reply_ptr -= (reply_len-prefix_len);
+				reply_len = prefix_len;
+				macii_state = read_done;
+				break;
+			} /* end timeout / SRQ handling for II hw. */
+
+			if((reply_len-prefix_len)>3
+				&& memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+			{
+				/* SRQ tacked on data packet */
+				/* Terminate the packet (SRQ never ends) */
+				x = via[SR];
+				macii_state = read_done;
+				reply_len -= 3;
+				reply_ptr -= 3;
+				need_poll = 1;
+				/* need to continue; next byte not seen else */
+			} else {
+				/* Sanity check */
+				if (reply_len > 15) reply_len = 0;
+				/* read byte */
+				x = via[SR];
+				*reply_ptr = x;
+				reply_ptr++;
+				reply_len++;
+			}
+			/* The usual handshake ... */
+
+			/*
+			 * NetBSD hints that the next to last byte 
+			 * is sent with IRQ !! 
+			 * Guido found out it's the last one (0x0),
+			 * but IRQ should be asserted already.
+			 * Problem with timeout detection: First
+			 * transition to /IRQ might be second 
+			 * byte of timeout packet! 
+			 * Timeouts are signaled by 4x FF.
+			 */
+			if (!(status & TREQ) && (x == 0x00)) { /* != 0xFF */
+				/* invert state bits, toggle ODD/EVEN */
+				via[B] ^= ST_MASK;
+
+				/* adjust packet length */
+				reply_len--;
+				reply_ptr--;
+				macii_state = read_done;
+			} else {
+				/* not caught: ST_CMD */
+				/* required for re-entry 'reading'! */
+				if ((status & ST_MASK) == ST_IDLE) {
+					/* (in)sanity check - set even */
+					via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+				} else {
+					/* invert state bits */
+					via[B] ^= ST_MASK;
+				}
+			}
+			break;
+
+		case read_done:
+			x = via[SR];
+			if (reading_reply) {
+				req = current_req;
+				req->reply_len = reply_ptr - req->reply;
+				req->complete = 1;
+				current_req = req->next;
+				if (req->done) (*req->done)(req);
+			} else {
+				adb_input(reply_buf, reply_ptr - reply_buf,
+					  regs, 0);
+			}
+
+			/*
+			 * remember this device ID; it's the latest we got a 
+			 * reply from!
+			 */
+			last_reply = command_byte;
+			last_active = (command_byte & 0xF0) >> 4;
+
+			/* SRQ seen before, initiate poll now */
+			if (need_poll) {
+				macii_state = idle;
+				macii_queue_poll();
+				need_poll = 0;
+				break;
+			}
+
+			/* /IRQ seen, so the ADB controller has data for us */
+			if (!(status & TREQ)) {
+				/* set ADB state to idle */
+				via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+
+				macii_state = reading;
+
+				reply_buf[0] = command_byte;
+				reply_ptr = reply_buf + 1;
+				reply_len = 1;
+				prefix_len = 1;
+				reading_reply = 0;
+			} else {
+				/* no IRQ, send next packet or wait */
+				macii_state = idle;
+				if (current_req)
+					macii_start();
+				else
+					macii_retransmit(last_active);
+			}
+			break;
+
+		default:
+		break;
+	}
+	/* reset mutex and interrupts */
+	driver_running = 0;
+	restore_flags(flags);
+}
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/via-maciisi.c linux/drivers/macintosh/via-maciisi.c
--- v2.3.44/linux/drivers/macintosh/via-maciisi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/via-maciisi.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,486 @@
+/*
+ * Device driver for the IIsi-style ADB on some Mac LC and II-class machines
+ *
+ * Based on via-cuda.c and via-macii.c, as well as the original
+ * adb-bus.c, which in turn is somewhat influenced by (but uses no
+ * code from) the NetBSD HWDIRECT ADB code.  Original IIsi driver work
+ * was done by Robert Thompson and integrated into the old style
+ * driver by Michael Schmitz.
+ *
+ * Original sources (c) Alan Cox, Paul Mackerras, and others.
+ *
+ * Rewritten for Unified ADB by David Huggins-Daines <dhd@debian.org> */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/delay.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */
+#define RS		0x200		/* skip between registers */
+#define B		0		/* B-side data */
+#define A		RS		/* A-side data */
+#define DIRB		(2*RS)		/* B-side direction (1=output) */
+#define DIRA		(3*RS)		/* A-side direction (1=output) */
+#define SR		(10*RS)		/* Shift register */
+#define ACR		(11*RS)		/* Auxiliary control register */
+#define IFR		(13*RS)		/* Interrupt flag register */
+#define IER		(14*RS)		/* Interrupt enable register */
+
+/* Bits in B data register: all active low */
+#define TREQ		0x08		/* Transfer request (input) */
+#define TACK		0x10		/* Transfer acknowledge (output) */
+#define TIP		0x20		/* Transfer in progress (output) */
+#define ST_MASK		0x30		/* mask for selecting ADB state bits */
+
+/* Bits in ACR */
+#define SR_CTRL		0x1c		/* Shift register control bits */
+#define SR_EXT		0x0c		/* Shift on external clock */
+#define SR_OUT		0x10		/* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET		0x80		/* set bits in IER */
+#define IER_CLR		0		/* clear bits in IER */
+#define SR_INT		0x04		/* Shift register full/empty */
+#define SR_DATA		0x08		/* Shift register data */
+#define SR_CLOCK	0x10		/* Shift register clock */
+
+#define ADB_DELAY 150
+
+static struct adb_request* current_req = NULL;
+static struct adb_request* last_req = NULL;
+static unsigned char maciisi_rbuf[16];
+static unsigned char *reply_ptr = NULL;
+static int data_index;
+static int reading_reply;
+static int reply_len;
+
+static enum maciisi_state {
+    idle,
+    sending,
+    reading,
+} maciisi_state;
+
+static int maciisi_probe(void);
+static int maciisi_init(void);
+static int maciisi_send_request(struct adb_request* req, int sync);
+static int maciisi_write(struct adb_request* req);
+static void maciisi_interrupt(int irq, void* arg, struct pt_regs* regs);
+static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs);
+static int maciisi_init_via(void);
+static void maciisi_poll(void);
+static void maciisi_start(void);
+
+struct adb_driver via_maciisi_driver = {
+	"Mac IIsi",
+	maciisi_probe,
+	maciisi_init,
+	maciisi_send_request,
+	NULL, /* maciisi_adb_autopoll, */
+	maciisi_poll,
+	NULL /* maciisi_reset_adb_bus */
+};
+
+static int
+maciisi_probe(void)
+{
+	if (macintosh_config->adb_type != MAC_ADB_IISI)
+		return -ENODEV;
+
+	via = via1;
+	return 0;
+}
+
+static int
+maciisi_init(void)
+{
+	int err;
+
+	if (via == NULL)
+		return -ENODEV;
+
+	if ((err = maciisi_init_via())) {
+		printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err);
+		via = NULL;
+		return err;
+	}
+
+	if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK, 
+			"ADB", maciisi_interrupt)) {
+		printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB);
+		return -EAGAIN;
+	}
+
+	printk("adb: Mac IIsi driver v0.1 for Unified ADB.\n");
+	return 0;
+}
+
+static void
+maciisi_stfu(void)
+{
+	int status = via[B] & (TIP|TREQ);
+
+	if (status & TREQ) {
+		printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n");
+		return;
+	}
+
+	/* start transfer */
+	via[B] |= TIP;
+	while (!(status & TREQ)) {
+		int poll_timeout = ADB_DELAY * 5;
+		/* Poll for SR interrupt */
+		while (!(via[IFR] & SR_INT) && poll_timeout-- > 0)
+			status = via[B] & (TIP|TREQ);
+		via[SR]; /* Clear shift register */
+		printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d\n",
+		       status, poll_timeout);
+		
+		/* ACK on-off */
+		via[B] |= TACK;
+		udelay(ADB_DELAY);
+		via[B] &= ~TACK;
+	}
+	/* end frame */
+	via[B] &= ~TIP;
+}
+
+/* All specifically VIA-related initialization goes here */
+static int
+maciisi_init_via(void)
+{
+	/* Set the lines up. We want TREQ as input TACK|TIP as output */
+	via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
+	/* Shift register on input */
+	via[ACR]  = (via[ACR] & ~SR_CTRL) | SR_EXT;
+	printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ));
+	/* Set initial state: idle */
+	via[B] &= ~(TACK|TIP);
+	/* Wipe any pending data and int */
+	via[SR];
+	if (!(via[B] & TREQ))
+		maciisi_stfu();
+	via[IER] = IER_SET | SR_INT;
+	maciisi_state = idle;
+	return 0;
+}
+
+/* Send a request, possibly waiting for a reply */
+static int
+maciisi_send_request(struct adb_request* req, int sync)
+{
+	int i;
+	static int dump_packet = 1;
+
+	if (via == NULL) {
+		req->complete = 1;
+		return -ENXIO;
+	}
+
+	if (dump_packet) {
+		printk(KERN_DEBUG "maciisi_send_request:");
+		for (i = 0; i < req->nbytes; i++) {
+			printk(" %.2x", req->data[i]);
+		}
+		printk("\n");
+	}
+	req->reply_expected = 1;
+	
+	i = maciisi_write(req);
+	if (i)
+		return i;
+	
+	if (sync) {
+		while (!req->complete) {
+			maciisi_poll();
+		}
+	}
+	return 0;
+}
+
+/* Enqueue a request, and run the queue if possible */
+static int
+maciisi_write(struct adb_request* req)
+{
+	unsigned long flags;
+
+  	printk(KERN_DEBUG "maciisi_write called, state=%d ifr=%x\n", maciisi_state, via[IFR]);
+	/* We will accept CUDA packets - the VIA sends them to us, so
+           it figures that we should be able to send them to it */
+	if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
+		printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n");
+		req->complete = 1;
+		return -EINVAL;
+	}
+	req->next = 0;
+	req->sent = 0;
+	req->complete = 0;
+	req->reply_len = 0;
+	save_flags(flags); cli();
+
+	if (current_req) {
+		last_req->next = req;
+		last_req = req;
+	} else {
+		current_req = req;
+		last_req = req;
+	}
+	if (maciisi_state == idle)
+		maciisi_start();
+	else
+		printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state);
+
+	restore_flags(flags);
+	return 0;
+}
+
+static void
+maciisi_start(void)
+{
+	struct adb_request* req;
+	int status;
+
+	printk(KERN_DEBUG "maciisi_start called, state=%d, ifr=%x\n", maciisi_state, via[IFR]);
+	if (maciisi_state != idle) {
+		/* shouldn't happen */
+		printk(KERN_ERR "maciisi_start: maciisi_start called when driver busy!\n");
+		return;
+	}
+
+	req = current_req;
+	if (req == NULL)
+		return;
+
+	status = via[B] & (TIP|TREQ);
+	if (!(status & TREQ)) {
+		/* Bus is busy, set up for reading */
+		printk(KERN_DEBUG "maciisi_start: bus busy - aborting\n");
+		return;
+	}
+
+	/* Okay, send */
+	printk(KERN_DEBUG "maciisi_start: sending\n");
+	/* Set state to active */
+	via[B] |= TIP;
+	/* ACK off */
+	via[B] &= ~TACK;
+	/* Shift out and send */
+	via[ACR] |= SR_OUT;
+	via[SR] = req->data[0];
+	data_index = 1;
+	/* ACK on */
+	via[B] |= TACK;
+	maciisi_state = sending;
+}
+
+void
+maciisi_poll(void)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (via[IFR] & SR_INT) {
+		maciisi_interrupt(0, 0, 0);
+	}
+	restore_flags(flags);
+}
+
+/* Shift register interrupt - this is *supposed* to mean that the
+   register is either full or empty. In practice, I have no idea what
+   it means :( */
+static void
+maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
+{
+	int status;
+	struct adb_request *req;
+	static int dump_reply = 1;
+
+	if (!(via[IFR] & SR_INT)) {
+		/* Shouldn't happen, we hope */
+		printk(KERN_DEBUG "maciisi_interrupt: called without interrupt flag set\n");
+		return;
+	}
+
+	status = via[B] & (TIP|TREQ);
+	printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]);
+
+ switch_start:
+	switch (maciisi_state) {
+	case idle:
+		printk(KERN_DEBUG "maciisi_interrupt: state=idle, status %x\n", status);
+		if (status & TIP)
+			printk(KERN_DEBUG "maciisi_interrupt: state is idle but TIP asserted!\n");
+
+		udelay(ADB_DELAY);
+		/* Shift in */
+		via[ACR] &= ~SR_OUT;
+ 		/* Signal start of frame */
+		via[B] |= TIP;
+		/* Clear the interrupt (throw this value on the floor, it's useless) */
+		via[SR];
+		/* ACK adb chip, high-low */
+		via[B] |= TACK;
+		udelay(ADB_DELAY);
+		via[B] &= ~TACK;
+		reply_len = 0;
+		maciisi_state = reading;
+		if (reading_reply) {
+			reply_ptr = current_req->reply;
+		} else {
+			printk(KERN_DEBUG "maciisi_interrupt: received unsolicited packet\n");
+			reply_ptr = maciisi_rbuf;
+		}
+		break;
+
+	case sending:
+		printk(KERN_DEBUG "maciisi_interrupt: state=sending, status=%x\n", status);
+		/* Clear interrupt */
+		via[SR];
+		/* Set ACK off */
+		via[B] &= ~TACK;
+		req = current_req;
+
+		if (!(status & TREQ)) {
+			/* collision */
+			printk(KERN_DEBUG "maciisi_interrupt: send collision\n");
+			/* Set idle and input */
+			via[B] &= ~TIP;
+			via[ACR] &= ~SR_OUT;
+			/* Must re-send */
+			reading_reply = 0;
+			reply_len = 0;
+			maciisi_state = idle;
+			/* process this now, because the IFR has been cleared */
+			goto switch_start;
+		}
+
+		if (data_index >= req->nbytes) {
+			/* Sent the whole packet, put the bus back in idle state */
+			/* Shift in, we are about to read a reply (hopefully) */
+			via[ACR] &= ~SR_OUT;
+			/* End of frame */
+			via[B] &= ~TIP;
+			req->sent = 1;
+			maciisi_state = idle;
+			if (req->reply_expected) {
+				/* Note: only set this once we've
+                                   successfully sent the packet */
+				reading_reply = 1;
+			} else {
+				current_req = req->next;
+				if (req->done)
+					(*req->done)(req);
+			}
+		} else {
+			/* Sending more stuff */
+			/* Shift out */
+			via[ACR] |= SR_OUT;
+			/* Delay */
+			udelay(ADB_DELAY);
+			/* Write */
+			via[SR] = req->data[data_index++];
+			/* Signal 'byte ready' */
+			via[B] |= TACK;
+		}
+		break;
+
+	case reading:
+		printk(KERN_DEBUG "maciisi_interrupt: state=reading, status=%x\n", status);
+		/* Shift in */
+		via[ACR] &= ~SR_OUT;
+		if (reply_len++ > 16) {
+			printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n");
+			via[B] |= TACK;
+			udelay(ADB_DELAY);
+			via[B] &= ~(TACK|TIP);
+			maciisi_state = idle;
+			maciisi_start();
+			break;
+		}
+		*reply_ptr++ = via[SR];
+		status = via[B] & (TIP|TREQ);
+		/* ACK on/off */
+		via[B] |= TACK;
+		udelay(ADB_DELAY);
+		via[B] &= ~TACK;	
+		if (!(status & TREQ))
+			break; /* more stuff to deal with */
+		
+		/* end of frame */
+		via[B] &= ~TIP;
+
+		/* end of packet, deal with it */
+		if (reading_reply) {
+			req = current_req;
+			req->reply_len = reply_ptr - req->reply;
+			if (req->data[0] == ADB_PACKET) {
+				/* Have to adjust the reply from ADB commands */
+				if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
+					/* the 0x2 bit indicates no response */
+					req->reply_len = 0;
+				} else {
+					/* leave just the command and result bytes in the reply */
+					req->reply_len -= 2;
+					memmove(req->reply, req->reply + 2, req->reply_len);
+				}
+			}
+			if (dump_reply) {
+				int i;
+				printk(KERN_DEBUG "maciisi_interrupt: reply is ");
+				for (i = 0; i < req->reply_len; ++i)
+					printk(" %.2x", req->reply[i]);
+				printk("\n");
+			}
+			req->complete = 1;
+			current_req = req->next;
+			if (req->done)
+				(*req->done)(req);
+			/* Obviously, we got it */
+			reading_reply = 0;
+		} else {
+			maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs);
+		}
+		maciisi_state = idle;
+		status = via[B] & (TIP|TREQ);
+		if (!(status & TREQ)) {
+			/* Timeout?! */
+			printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n",
+			       status, via[IFR]);
+			maciisi_stfu();
+		}
+		/* Do any queued requests now if possible */
+		maciisi_start();
+		break;
+
+	default:
+		printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
+	}
+}
+
+static void
+maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+    int i;
+
+    switch (buf[0]) {
+    case ADB_PACKET:
+	    adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
+	    break;
+    default:
+	    printk(KERN_DEBUG "data from IIsi ADB (%d bytes):", nb);
+	    for (i = 0; i < nb; ++i)
+		    printk(" %.2x", buf[i]);
+	    printk("\n");
+
+    }
+}
diff -u --recursive --new-file v2.3.44/linux/drivers/macintosh/via-pmu68k.c linux/drivers/macintosh/via-pmu68k.c
--- v2.3.44/linux/drivers/macintosh/via-pmu68k.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/via-pmu68k.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,1064 @@
+/*
+ * Device driver for the PMU on 68K-based Apple PowerBooks
+ *
+ * The VIA (versatile interface adapter) interfaces to the PMU,
+ * a 6805 microprocessor core whose primary function is to control
+ * battery charging and system power on the PowerBooks.
+ * The PMU also controls the ADB (Apple Desktop Bus) which connects
+ * to the keyboard and mouse, as well as the non-volatile RAM
+ * and the RTC (real time clock) chip.
+ *
+ * Adapted for 68K PMU by Joshua M. Thompson
+ *
+ * Based largely on the PowerMac PMU code by Paul Mackerras and
+ * Fabio Riccardi.
+ *
+ * Also based on the PMU driver from MkLinux by Apple Computer, Inc.
+ * and the Open Software Foundation, Inc.
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* Misc minor number allocated for /dev/pmu */
+#define PMU_MINOR	154
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS		0x200		/* skip between registers */
+#define B		0		/* B-side data */
+#define A		RS		/* A-side data */
+#define DIRB		(2*RS)		/* B-side direction (1=output) */
+#define DIRA		(3*RS)		/* A-side direction (1=output) */
+#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
+#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
+#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
+#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */
+#define SR		(10*RS)		/* Shift register */
+#define ACR		(11*RS)		/* Auxiliary control register */
+#define PCR		(12*RS)		/* Peripheral control register */
+#define IFR		(13*RS)		/* Interrupt flag register */
+#define IER		(14*RS)		/* Interrupt enable register */
+#define ANH		(15*RS)		/* A-side data, no handshake */
+
+/* Bits in B data register: both active low */
+#define TACK		0x02		/* Transfer acknowledge (input) */
+#define TREQ		0x04		/* Transfer request (output) */
+
+/* Bits in ACR */
+#define SR_CTRL		0x1c		/* Shift register control bits */
+#define SR_EXT		0x0c		/* Shift on external clock */
+#define SR_OUT		0x10		/* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define SR_INT		0x04		/* Shift register full/empty */
+#define CB1_INT		0x10		/* transition on CB1 input */
+
+static enum pmu_state {
+	idle,
+	sending,
+	intack,
+	reading,
+	reading_intr,
+} pmu_state;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static struct adb_request *req_awaiting_reply;
+static unsigned char interrupt_data[32];
+static unsigned char *reply_ptr;
+static int data_index;
+static int data_len;
+static int adb_int_pending;
+static int pmu_adb_flags;
+static int adb_dev_map = 0;
+static struct adb_request bright_req_1, bright_req_2, bright_req_3;
+static int pmu_kind = PMU_UNKNOWN;
+static int pmu_fully_inited = 0;
+
+int asleep;
+struct notifier_block *sleep_notifier_list;
+
+static int pmu_probe(void);
+static int pmu_init(void);
+static void pmu_start(void);
+static void pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
+static int pmu_send_request(struct adb_request *req, int sync);
+static int pmu_autopoll(int devs);
+void pmu_poll(void);
+static int pmu_reset_bus(void);
+static int pmu_queue_request(struct adb_request *req);
+
+static void pmu_start(void);
+static void send_byte(int x);
+static void recv_byte(void);
+static void pmu_done(struct adb_request *req);
+static void pmu_handle_data(unsigned char *data, int len,
+			    struct pt_regs *regs);
+static void set_volume(int level);
+
+struct adb_driver via_pmu_driver = {
+	"68K PMU",
+	pmu_probe,
+	pmu_init,
+	pmu_send_request,
+	pmu_autopoll,
+	pmu_poll,
+	pmu_reset_bus
+};
+
+/*
+ * This table indicates for each PMU opcode:
+ * - the number of data bytes to be sent with the command, or -1
+ *   if a length byte should be sent,
+ * - the number of response bytes which the PMU will return, or
+ *   -1 if it will send a length byte.
+ */
+static s8 pmu_data_len[256][2] = {
+/*	   0	   1	   2	   3	   4	   5	   6	   7  */
+/*00*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*08*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*10*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*18*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*20*/	{-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*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},
+/*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, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
+/*50*/	{ 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
+/*58*/	{ 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
+/*60*/	{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*68*/	{ 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
+/*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},{ 5, 1},{ 4, 1},{ 4, 1},
+/*80*/	{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*88*/	{ 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*90*/	{ 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*98*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*a0*/	{ 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
+/*a8*/	{ 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*b0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*b8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*c0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*c8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*d0*/	{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*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},{ 4, 0},{-1, 0},{-1, 0},
+/*e8*/	{ 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
+/*f0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*f8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+};
+
+int pmu_probe()
+{
+	if (macintosh_config->adb_type == MAC_ADB_PB1) {
+		pmu_kind = PMU_68K_V1;
+	} else if (macintosh_config->adb_type == MAC_ADB_PB2) {
+		pmu_kind = PMU_68K_V2;
+	} else {
+		return -ENODEV;
+	}
+
+	pmu_state = idle;
+
+	return 0;
+}
+
+static int 
+pmu_init(void)
+{
+	int timeout;
+	volatile struct adb_request req;
+
+	via2[B] |= TREQ;				/* negate TREQ */
+	via2[DIRB] = (via2[DIRB] | TREQ) & ~TACK;	/* TACK in, TREQ out */
+
+	pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB);
+	timeout =  100000;
+	while (!req.complete) {
+		if (--timeout < 0) {
+			printk(KERN_ERR "pmu_init: no response from PMU\n");
+			return -EAGAIN;
+		}
+		udelay(10);
+		pmu_poll();
+	}
+
+	/* ack all pending interrupts */
+	timeout = 100000;
+	interrupt_data[0] = 1;
+	while (interrupt_data[0] || pmu_state != idle) {
+		if (--timeout < 0) {
+			printk(KERN_ERR "pmu_init: timed out acking intrs\n");
+			return -EAGAIN;
+		}
+		if (pmu_state == idle) {
+			adb_int_pending = 1;
+			pmu_interrupt(0, NULL, NULL);
+		}
+		pmu_poll();
+		udelay(10);
+	}
+
+	pmu_request((struct adb_request *) &req, NULL, 2, PMU_SET_INTR_MASK,
+			PMU_INT_ADB_AUTO|PMU_INT_SNDBRT|PMU_INT_ADB);
+	timeout =  100000;
+	while (!req.complete) {
+		if (--timeout < 0) {
+			printk(KERN_ERR "pmu_init: no response from PMU\n");
+			return -EAGAIN;
+		}
+		udelay(10);
+		pmu_poll();
+	}
+
+	bright_req_1.complete = 1;
+	bright_req_2.complete = 1;
+	bright_req_3.complete = 1;
+
+	if (request_irq(IRQ_MAC_ADB_SR, pmu_interrupt, 0, "pmu-shift",
+			pmu_interrupt)) {
+		printk(KERN_ERR "pmu_init: can't get irq %d\n",
+			IRQ_MAC_ADB_SR);
+		return -EAGAIN;
+	}
+	if (request_irq(IRQ_MAC_ADB_CL, pmu_interrupt, 0, "pmu-clock",
+			pmu_interrupt)) {
+		printk(KERN_ERR "pmu_init: can't get irq %d\n",
+			IRQ_MAC_ADB_CL);
+		free_irq(IRQ_MAC_ADB_SR, pmu_interrupt);
+		return -EAGAIN;
+	}
+
+	pmu_fully_inited = 1;
+	
+	/* Enable backlight */
+	pmu_enable_backlight(1);
+
+	printk("adb: PMU 68K driver v0.5 for Unified ADB.\n");
+
+	return 0;
+}
+
+int
+pmu_get_model(void)
+{
+	return pmu_kind;
+}
+
+/* Send an ADB command */
+static int 
+pmu_send_request(struct adb_request *req, int sync)
+{
+    int i, ret;
+
+    if (!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;
+		case CUDA_GET_PRAM:
+			if (req->nbytes != 4)
+				break;
+			req->data[0] = PMU_READ_NVRAM;
+			req->data[1] = req->data[2];
+			req->data[2] = req->data[3];
+			req->nbytes = 3;
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_GET_PRAM;
+			ret = pmu_queue_request(req);
+			break;
+		case CUDA_SET_PRAM:
+			if (req->nbytes != 5)
+				break;
+			req->data[0] = PMU_WRITE_NVRAM;
+			req->data[1] = req->data[2];
+			req->data[2] = req->data[3];
+			req->data[3] = req->data[4];
+			req->nbytes = 4;
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_SET_PRAM;
+			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;
+}
+
+/* Enable/disable autopolling */
+static int 
+pmu_autopoll(int devs)
+{
+	struct adb_request req;
+
+	if (!pmu_fully_inited) return -ENXIO;
+
+	if (devs) {
+		adb_dev_map = devs;
+		pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
+			    adb_dev_map >> 8, adb_dev_map);
+		pmu_adb_flags = 2;
+	} else {
+		pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
+		pmu_adb_flags = 0;
+	}
+	while (!req.complete)
+		pmu_poll();
+	return 0;
+}
+
+/* Reset the ADB bus */
+static int 
+pmu_reset_bus(void)
+{
+	struct adb_request req;
+	long timeout;
+	int save_autopoll = adb_dev_map;
+
+	if (!pmu_fully_inited) return -ENXIO;
+
+	/* anyone got a better idea?? */
+	pmu_autopoll(0);
+
+	req.nbytes = 5;
+	req.done = NULL;
+	req.data[0] = PMU_ADB_CMD;
+	req.data[1] = 0;
+	req.data[2] = 3; /* ADB_BUSRESET ??? */
+	req.data[3] = 0;
+	req.data[4] = 0;
+	req.reply_len = 0;
+	req.reply_expected = 1;
+	if (pmu_queue_request(&req) != 0)
+	{
+		printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
+		return -EIO;
+	}
+	while (!req.complete)
+		pmu_poll();
+	timeout = 100000;
+	while (!req.complete) {
+		if (--timeout < 0) {
+			printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
+			return -EIO;
+		}
+		udelay(10);
+		pmu_poll();
+	}
+
+	if (save_autopoll != 0)
+		pmu_autopoll(save_autopoll);
+		
+	return 0;
+}
+
+/* Construct and send a pmu request */
+int 
+pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
+	    int nbytes, ...)
+{
+	va_list list;
+	int i;
+
+	if (nbytes < 0 || nbytes > 32) {
+		printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
+		req->complete = 1;
+		return -EINVAL;
+	}
+	req->nbytes = nbytes;
+	req->done = done;
+	va_start(list, nbytes);
+	for (i = 0; i < nbytes; ++i)
+		req->data[i] = va_arg(list, int);
+	va_end(list);
+	if (pmu_data_len[req->data[0]][1] != 0) {
+		req->reply[0] = ADB_RET_OK;
+		req->reply_len = 1;
+	} else
+		req->reply_len = 0;
+	req->reply_expected = 0;
+	return pmu_queue_request(req);
+}
+
+static int 
+pmu_queue_request(struct adb_request *req)
+{
+	unsigned long flags;
+	int nsend;
+
+	if (req->nbytes <= 0) {
+		req->complete = 1;
+		return 0;
+	}
+	nsend = pmu_data_len[req->data[0]][0];
+	if (nsend >= 0 && req->nbytes != nsend + 1) {
+		req->complete = 1;
+		return -EINVAL;
+	}
+
+	req->next = 0;
+	req->sent = 0;
+	req->complete = 0;
+	save_flags(flags); cli();
+
+	if (current_req != 0) {
+		last_req->next = req;
+		last_req = req;
+	} else {
+		current_req = req;
+		last_req = req;
+		if (pmu_state == idle)
+			pmu_start();
+	}
+
+	restore_flags(flags);
+	return 0;
+}
+
+static void 
+send_byte(int x)
+{
+	via1[ACR] |= SR_CTRL;
+	via1[SR] = x;
+	via2[B] &= ~TREQ;		/* assert TREQ */
+}
+
+static void 
+recv_byte()
+{
+	char c;
+
+	via1[ACR] = (via1[ACR] | SR_EXT) & ~SR_OUT;
+	c = via1[SR];		/* resets SR */
+	via2[B] &= ~TREQ;
+}
+
+static void 
+pmu_start()
+{
+	unsigned long flags;
+	struct adb_request *req;
+
+	/* assert pmu_state == idle */
+	/* get the packet to send */
+	save_flags(flags); cli();
+	req = current_req;
+	if (req == 0 || pmu_state != idle
+	    || (req->reply_expected && req_awaiting_reply))
+		goto out;
+
+	pmu_state = sending;
+	data_index = 1;
+	data_len = pmu_data_len[req->data[0]][0];
+
+	/* set the shift register to shift out and send a byte */
+	send_byte(req->data[0]);
+
+out:
+	restore_flags(flags);
+}
+
+void 
+pmu_poll()
+{
+	unsigned long cpu_flags;
+
+	save_flags(cpu_flags);
+	cli();
+	if (via1[IFR] & SR_INT) {
+		via1[IFR] = SR_INT;
+		pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL);
+	}
+	if (via1[IFR] & CB1_INT) {
+		via1[IFR] = CB1_INT;
+		pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL);
+	}
+	restore_flags(cpu_flags);
+}
+
+static void 
+pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct adb_request *req;
+	int timeout, bite = 0;	/* to prevent compiler warning */
+
+#if 0
+	printk("pmu_interrupt: irq %d state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",
+		irq, pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);
+#endif
+
+	if (irq == IRQ_MAC_ADB_CL) {		/* CB1 interrupt */
+		adb_int_pending = 1;
+	} else if (irq == IRQ_MAC_ADB_SR) {	/* SR interrupt  */
+		if (via2[B] & TACK) {
+			printk(KERN_DEBUG "PMU: SR_INT but ack still high! (%x)\n", via2[B]);
+		}
+
+		/* if reading grab the byte */
+		if ((via1[ACR] & SR_OUT) == 0) bite = via1[SR];
+
+		/* reset TREQ and wait for TACK to go high */
+		via2[B] |= TREQ;
+		timeout = 3200;
+		while (!(via2[B] & TACK)) {
+			if (--timeout < 0) {
+				printk(KERN_ERR "PMU not responding (!ack)\n");
+				goto finish;
+			}
+			udelay(10);
+		}
+
+		switch (pmu_state) {
+		case sending:
+			req = current_req;
+			if (data_len < 0) {
+				data_len = req->nbytes - 1;
+				send_byte(data_len);
+				break;
+			}
+			if (data_index <= data_len) {
+				send_byte(req->data[data_index++]);
+				break;
+			}
+			req->sent = 1;
+			data_len = pmu_data_len[req->data[0]][1];
+			if (data_len == 0) {
+				pmu_state = idle;
+				current_req = req->next;
+				if (req->reply_expected)
+					req_awaiting_reply = req;
+				else
+					pmu_done(req);
+			} else {
+				pmu_state = reading;
+				data_index = 0;
+				reply_ptr = req->reply + req->reply_len;
+				recv_byte();
+			}
+			break;
+
+		case intack:
+			data_index = 0;
+			data_len = -1;
+			pmu_state = reading_intr;
+			reply_ptr = interrupt_data;
+			recv_byte();
+			break;
+
+		case reading:
+		case reading_intr:
+			if (data_len == -1) {
+				data_len = bite;
+				if (bite > 32)
+					printk(KERN_ERR "PMU: bad reply len %d\n",
+					       bite);
+			} else {
+				reply_ptr[data_index++] = bite;
+			}
+			if (data_index < data_len) {
+				recv_byte();
+				break;
+			}
+
+			if (pmu_state == reading_intr) {
+				pmu_handle_data(interrupt_data, data_index, regs);
+			} else {
+				req = current_req;
+				current_req = req->next;
+				req->reply_len += data_index;
+				pmu_done(req);
+			}
+			pmu_state = idle;
+
+			break;
+
+		default:
+			printk(KERN_ERR "pmu_interrupt: unknown state %d?\n",
+			       pmu_state);
+		}
+	}
+finish:
+	if (pmu_state == idle) {
+		if (adb_int_pending) {
+			pmu_state = intack;
+			send_byte(PMU_INT_ACK);
+			adb_int_pending = 0;
+		} else if (current_req) {
+			pmu_start();
+		}
+	}
+
+#if 0
+	printk("pmu_interrupt: exit state %d acr %02X, b %02X data_index %d/%d adb_int_pending %d\n",
+		pmu_state, (uint) via1[ACR], (uint) via2[B], data_index, data_len, adb_int_pending);
+#endif
+}
+
+static void 
+pmu_done(struct adb_request *req)
+{
+	req->complete = 1;
+	if (req->done)
+		(*req->done)(req);
+}
+
+/* Interrupt data could be the result data from an ADB cmd */
+static void 
+pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+{
+	static int show_pmu_ints = 1;
+
+	asleep = 0;
+	if (len < 1) {
+		adb_int_pending = 0;
+		return;
+	}
+	if (data[0] & PMU_INT_ADB) {
+		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
+			struct adb_request *req = req_awaiting_reply;
+			if (req == 0) {
+				printk(KERN_ERR "PMU: extra ADB reply\n");
+				return;
+			}
+			req_awaiting_reply = 0;
+			if (len <= 2)
+				req->reply_len = 0;
+			else {
+				memcpy(req->reply, data + 1, len - 1);
+				req->reply_len = len - 1;
+			}
+			pmu_done(req);
+		} else {
+			adb_input(data+1, len-1, regs, 1);
+		}
+	} else {
+		if (data[0] == 0x08 && len == 3) {
+			/* sound/brightness buttons pressed */
+			pmu_set_brightness(data[1] >> 3);
+			set_volume(data[2]);
+		} else if (show_pmu_ints
+			   && !(data[0] == PMU_INT_TICK && len == 1)) {
+			int i;
+			printk(KERN_DEBUG "pmu intr");
+			for (i = 0; i < len; ++i)
+				printk(" %.2x", data[i]);
+			printk("\n");
+		}
+	}
+}
+
+int backlight_level = -1;
+int backlight_enabled = 0;
+
+#define LEVEL_TO_BRIGHT(lev)	((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
+
+void 
+pmu_enable_backlight(int on)
+{
+	struct adb_request req;
+
+	if (on) {
+	    /* first call: get current backlight value */
+	    if (backlight_level < 0) {
+		switch(pmu_kind) {
+		    case PMU_68K_V1:
+		    case PMU_68K_V2:
+			pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
+			while (!req.complete)
+				pmu_poll();
+			printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);
+			backlight_level = req.reply[1];
+			break;
+		    default:
+		        backlight_enabled = 0;
+		        return;
+		}
+	    }
+	    pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+	    	LEVEL_TO_BRIGHT(backlight_level));
+	    while (!req.complete)
+		pmu_poll();
+	}
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+	    PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
+	while (!req.complete)
+		pmu_poll();
+	backlight_enabled = on;
+}
+
+void 
+pmu_set_brightness(int level)
+{
+	int bright;
+
+	backlight_level = level;
+	bright = LEVEL_TO_BRIGHT(level);
+	if (!backlight_enabled)
+		return;
+	if (bright_req_1.complete)
+		pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+		    bright);
+	if (bright_req_2.complete)
+		pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
+		    PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
+}
+
+void 
+pmu_enable_irled(int on)
+{
+	struct adb_request req;
+
+	pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
+	    (on ? PMU_POW_ON : PMU_POW_OFF));
+	while (!req.complete)
+		pmu_poll();
+}
+
+static void 
+set_volume(int level)
+{
+}
+
+int
+pmu_present(void)
+{
+	return (pmu_kind != PMU_UNKNOWN);
+}
+
+#if 0 /* needs some work for 68K */
+
+/*
+ * This struct is used to store config register values for
+ * PCI devices which may get powered off when we sleep.
+ */
+static struct pci_save {
+	u16	command;
+	u16	cache_lat;
+	u16	intr;
+} *pbook_pci_saves;
+static int n_pbook_pci_saves;
+
+static inline void __openfirmware
+pbook_pci_save(void)
+{
+	int npci;
+	struct pci_dev *pd;
+	struct pci_save *ps;
+
+	npci = 0;
+	for (pd = pci_devices; pd != NULL; pd = pd->next)
+		++npci;
+	n_pbook_pci_saves = npci;
+	if (npci == 0)
+		return;
+	ps = (struct pci_save *) kmalloc(npci * sizeof(*ps), GFP_KERNEL);
+	pbook_pci_saves = ps;
+	if (ps == NULL)
+		return;
+
+	for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) {
+		pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
+		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
+		++ps;
+		--npci;
+	}
+}
+
+static inline void __openfirmware
+pbook_pci_restore(void)
+{
+	u16 cmd;
+	struct pci_save *ps = pbook_pci_saves;
+	struct pci_dev *pd;
+	int j;
+
+	for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) {
+		if (ps->command == 0)
+			continue;
+		pci_read_config_word(pd, PCI_COMMAND, &cmd);
+		if ((ps->command & ~cmd) == 0)
+			continue;
+		switch (pd->hdr_type) {
+		case PCI_HEADER_TYPE_NORMAL:
+			for (j = 0; j < 6; ++j)
+				pci_write_config_dword(pd,
+					PCI_BASE_ADDRESS_0 + j*4,
+					pd->resource[j].start);
+			pci_write_config_dword(pd, PCI_ROM_ADDRESS,
+			       pd->resource[PCI_ROM_RESOURCE].start);
+			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
+				ps->cache_lat);
+			pci_write_config_word(pd, PCI_INTERRUPT_LINE,
+				ps->intr);
+			pci_write_config_word(pd, PCI_COMMAND, ps->command);
+			break;
+			/* other header types not restored at present */
+		}
+	}
+}
+
+/*
+ * Put the powerbook to sleep.
+ */
+#define IRQ_ENABLE	((unsigned int *)0xf3000024)
+#define MEM_CTRL	((unsigned int *)0xf8000070)
+
+int __openfirmware powerbook_sleep(void)
+{
+	int ret, i, x;
+	static int save_backlight;
+	static unsigned int save_irqen;
+	unsigned long msr;
+	unsigned int hid0;
+	unsigned long p, wait;
+	struct adb_request sleep_req;
+
+	/* Notify device drivers */
+	ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);
+	if (ret & NOTIFY_STOP_MASK)
+		return -EBUSY;
+
+	/* Sync the disks. */
+	/* XXX It would be nice to have some way to ensure that
+	 * nobody is dirtying any new buffers while we wait. */
+	fsync_dev(0);
+
+	/* Turn off the display backlight */
+	save_backlight = backlight_enabled;
+	if (save_backlight)
+		pmu_enable_backlight(0);
+
+	/* Give the disks a little time to actually finish writing */
+	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+		mb();
+
+	/* Disable all interrupts except pmu */
+	save_irqen = in_le32(IRQ_ENABLE);
+	for (i = 0; i < 32; ++i)
+		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
+			disable_irq(i);
+	asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+	/* Save the state of PCI config space for some slots */
+	pbook_pci_save();
+
+	/* Set the memory controller to keep the memory refreshed
+	   while we're asleep */
+	for (i = 0x403f; i >= 0x4000; --i) {
+		out_be32(MEM_CTRL, i);
+		do {
+			x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
+		} while (x == 0);
+		if (x >= 0x100)
+			break;
+	}
+
+	/* Ask the PMU to put us to sleep */
+	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+	while (!sleep_req.complete)
+		mb();
+	/* displacement-flush the L2 cache - necessary? */
+	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
+		i = *(volatile int *)p;
+	asleep = 1;
+
+	/* Put the CPU into sleep mode */
+	asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
+	asm volatile("mtspr 1008,%0" : : "r" (hid0));
+	save_flags(msr);
+	msr |= MSR_POW | MSR_EE;
+	restore_flags(msr);
+	udelay(10);
+
+	/* OK, we're awake again, start restoring things */
+	out_be32(MEM_CTRL, 0x3f);
+	pbook_pci_restore();
+
+	/* wait for the PMU interrupt sequence to complete */
+	while (asleep)
+		mb();
+
+	/* reenable interrupts */
+	for (i = 0; i < 32; ++i)
+		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
+			enable_irq(i);
+
+	/* Notify drivers */
+	notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
+
+	/* reenable ADB autopoll */
+	pmu_adb_autopoll(adb_dev_map);
+
+	/* Turn on the screen backlight, if it was on before */
+	if (save_backlight)
+		pmu_enable_backlight(1);
+
+	/* Wait for the hard disk to spin up */
+
+	return 0;
+}
+
+/*
+ * Support for /dev/pmu device
+ */
+static int __openfirmware pmu_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t __openfirmware pmu_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,
+			 size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+/* Note: removed __openfirmware here since it causes link errors */
+static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp,
+		     u_int cmd, u_long arg)
+{
+	int error;
+	__u32 value;
+
+	switch (cmd) {
+	    case PMU_IOC_SLEEP:
+	    	return -ENOSYS;
+	    case PMU_IOC_GET_BACKLIGHT:
+		return put_user(backlight_level, (__u32 *)arg);
+	    case PMU_IOC_SET_BACKLIGHT:
+		error = get_user(value, (__u32 *)arg);
+		if (!error)
+			pmu_set_brightness(value);
+		return error;
+	    case PMU_IOC_GET_MODEL:
+	    	return put_user(pmu_kind, (__u32 *)arg);
+	}
+	return -EINVAL;
+}
+
+static struct file_operations pmu_device_fops = {
+	NULL,		/* no seek */
+	pmu_read,
+	pmu_write,
+	NULL,		/* no readdir */
+	NULL,		/* no poll yet */
+	pmu_ioctl,
+	NULL,		/* no mmap */
+	pmu_open,
+	NULL,		/* flush */
+	NULL		/* no release */
+};
+
+static struct miscdevice pmu_device = {
+	PMU_MINOR, "pmu", &pmu_device_fops
+};
+
+void pmu_device_init(void)
+{
+	if (via)
+		misc_register(&pmu_device);
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
diff -u --recursive --new-file v2.3.44/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.3.44/linux/drivers/net/3c505.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/3c505.c	Sun Feb 13 18:20:21 2000
@@ -101,6 +101,7 @@
 #include <linux/in.h>
 #include <linux/malloc.h>
 #include <linux/ioport.h>
+#include <linux/spinlock.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -374,7 +375,7 @@
 static inline void prime_rx(struct net_device *dev)
 {
 	elp_device *adapter = dev->priv;
-	while (adapter->rx_active < ELP_RX_PCBS && dev->start) {
+	while (adapter->rx_active < ELP_RX_PCBS && test_bit(LINK_STATE_START, &dev->state)) {
 		if (!start_receive(dev, &adapter->itx_pcb))
 			break;
 	}
@@ -672,23 +673,10 @@
 	elp_device *adapter;
 	int timeout;
 
-	if (irq < 0 || irq > 15) {
-		printk("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq);
-		return;
-	}
 	dev = dev_id;
-
-	if (dev == NULL) {
-		printk("elp_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
 	adapter = (elp_device *) dev->priv;
-
-	if (dev->interrupt) {
-		printk("%s: re-entering the interrupt handler!\n", dev->name);
-		return;
-	}
-	dev->interrupt = 1;
+	
+	spin_lock(&adapter->lock);
 
 	do {
 		/*
@@ -702,20 +690,19 @@
 				printk("%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr));
 			}
 
-			outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR),
-				     dev);
+			outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
 			if (adapter->current_dma.direction) {
 				dev_kfree_skb_irq(adapter->current_dma.skb);
 			} else {
 				struct sk_buff *skb = adapter->current_dma.skb;
 				if (skb) {
-				  if (adapter->current_dma.target) {
-				    /* have already done the skb_put() */
-				    memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
-				  }
-				  skb->protocol = eth_type_trans(skb,dev);
-				  adapter->stats.rx_bytes += skb->len;
-				  netif_rx(skb);
+					if (adapter->current_dma.target) {
+				  	/* have already done the skb_put() */
+				  	memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
+					}
+					skb->protocol = eth_type_trans(skb,dev);
+					adapter->stats.rx_bytes += skb->len;
+					netif_rx(skb);
 				}
 			}
 			adapter->dmaing = 0;
@@ -733,15 +720,14 @@
 			check_3c505_dma(dev);
 		}
 
-		sti();
-
 		/*
 		 * receive a PCB from the adapter
 		 */
 		timeout = jiffies + 3*HZ/100;
 		while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
 			if (receive_pcb(dev, &adapter->irx_pcb)) {
-				switch (adapter->irx_pcb.command) {
+				switch (adapter->irx_pcb.command) 
+				{
 				case 0:
 					break;
 					/*
@@ -750,19 +736,15 @@
 				case 0xff:
 				case CMD_RECEIVE_PACKET_COMPLETE:
 					/* if the device isn't open, don't pass packets up the stack */
-					if (dev->start == 0)
+					if (test_bit(LINK_STATE_START, &dev->state) == 0)
 						break;
-					cli();
 					len = adapter->irx_pcb.data.rcv_resp.pkt_len;
 					dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
 					if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
-						printk("%s: interrupt - packet not received correctly\n", dev->name);
-						sti();
+						printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name);
 					} else {
 						if (elp_debug >= 3) {
-							sti();
 							printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
-							cli();
 						}
 						if (adapter->irx_pcb.command == 0xff) {
 							if (elp_debug >= 2)
@@ -772,7 +754,6 @@
 						} else {
 							receive_packet(dev, dlen);
 						}
-						sti();
 						if (elp_debug >= 3)
 							printk("%s: packet received\n", dev->name);
 					}
@@ -839,7 +820,7 @@
 				case CMD_TRANSMIT_PACKET_COMPLETE:
 					if (elp_debug >= 3)
 						printk("%s: interrupt - packet sent\n", dev->name);
-					if (dev->start == 0)
+					if (test_bit(LINK_STATE_START, &dev->state) == 0)
 						break;
 					switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
 					case 0xffff:
@@ -851,8 +832,7 @@
 						printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
 						break;
 					}
-					dev->tbusy = 0;
-					mark_bh(NET_BH);
+					netif_wake_queue(dev);
 					break;
 
 					/*
@@ -875,7 +855,7 @@
 	/*
 	 * indicate no longer in interrupt routine
 	 */
-	dev->interrupt = 0;
+	spin_unlock(&adapter->lock);
 }
 
 
@@ -913,16 +893,6 @@
 	adapter_reset(dev);
 
 	/*
-	 * interrupt routine not entered
-	 */
-	dev->interrupt = 0;
-
-	/*
-	 *  transmitter not busy
-	 */
-	dev->tbusy = 0;
-
-	/*
 	 * no receive PCBs active
 	 */
 	adapter->rx_active = 0;
@@ -931,6 +901,8 @@
 	adapter->send_pcb_semaphore = 0;
 	adapter->rx_backlog.in = 0;
 	adapter->rx_backlog.out = 0;
+	
+	spin_lock_init(&adapter->lock);
 
 	/*
 	 * install our interrupt service routine
@@ -1008,8 +980,8 @@
 	/*
 	 * device is now officially open!
 	 */
-	dev->start = 1;
 
+	netif_wake_queue(dev);
 	MOD_INC_USE_COUNT;
 
 	return 0;		/* Always succeed */
@@ -1085,6 +1057,25 @@
 	return TRUE;
 }
 
+/*
+ *	The upper layer thinks we timed out
+ */
+ 
+static void elp_timeout(struct net_device *dev)
+{
+	unsigned long flags;
+	elp_device *adapter = dev->priv;
+	int stat;
+
+	stat = inb_status(dev->base_addr);
+	printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
+	if (elp_debug >= 1)
+		printk("%s: status %#02x\n", dev->name, stat);
+	dev->trans_start = jiffies;
+	adapter->stats.tx_dropped++;
+	netif_wake_queue(dev);
+}
+
 /******************************************************
  *
  * start the transmitter
@@ -1094,40 +1085,17 @@
 
 static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	if (dev->interrupt) {
-		printk("%s: start_xmit aborted (in irq)\n", dev->name);
-		return 1;
-	}
-
+	unsigned long flags;
+	elp_device *adapter = dev->priv;
+	
+	spin_lock_irqsave(&adapter->lock, flags);
 	check_3c505_dma(dev);
 
-	/*
-	 * if the transmitter is still busy, we have a transmit timeout...
-	 */
-	if (dev->tbusy) {
-		elp_device *adapter = dev->priv;
-       		int tickssofar = jiffies - dev->trans_start;
-		int stat;
-
-		if (tickssofar < 1000)
-			return 1;
-
-		stat = inb_status(dev->base_addr);
-		printk("%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
-		if (elp_debug >= 1)
-			printk("%s: status %#02x\n", dev->name, stat);
-		dev->trans_start = jiffies;
-		dev->tbusy = 0;
-		adapter->stats.tx_dropped++;
-	}
-
 	if (elp_debug >= 3)
 		printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
 
-	if (test_and_set_bit(0, (void *) &dev->tbusy)) {
-		printk("%s: transmitter access conflict\n", dev->name);
-		return 1;
-	}
+	netif_stop_queue(dev);
+	
 	/*
 	 * send the packet at skb->data for skb->len
 	 */
@@ -1135,7 +1103,7 @@
 		if (elp_debug >= 2) {
 			printk("%s: failed to transmit packet\n", dev->name);
 		}
-		dev->tbusy = 0;
+		spin_unlock_irqrestore(&adapter->lock, flags);
 		return 1;
 	}
 	if (elp_debug >= 3)
@@ -1147,7 +1115,8 @@
 	dev->trans_start = jiffies;
 
 	prime_rx(dev);
-
+	spin_unlock_irqrestore(&adapter->lock, flags);
+	netif_start_queue(dev);
 	return 0;
 }
 
@@ -1166,7 +1135,7 @@
 
 	/* If the device is closed, just return the latest stats we have,
 	   - we cannot ask from the adapter without interrupts */
-	if (!dev->start)
+	if (!test_bit(LINK_STATE_START, &dev->state))
 		return &adapter->stats;
 
 	/* send a get statistics command to the board */
@@ -1203,6 +1172,8 @@
 	if (elp_debug >= 3)
 		printk("%s: request to close device\n", dev->name);
 
+	netif_stop_queue(dev);
+
 	/* Someone may request the device statistic information even when
 	 * the interface is closed. The following will update the statistics
 	 * structure in the driver, so we'll be able to give current statistics.
@@ -1215,16 +1186,6 @@
 	outb_control(0, dev);
 
 	/*
-	 *  flag transmitter as busy (i.e. not available)
-	 */
-	dev->tbusy = 1;
-
-	/*
-	 *  indicate device is closed
-	 */
-	dev->start = 0;
-
-	/*
 	 * release the IRQ
 	 */
 	free_irq(dev->irq, dev);
@@ -1252,10 +1213,13 @@
 	elp_device *adapter = (elp_device *) dev->priv;
 	struct dev_mc_list *dmi = dev->mc_list;
 	int i;
+	unsigned long flags;
 
 	if (elp_debug >= 3)
 		printk("%s: request to set multicast list\n", dev->name);
 
+	spin_lock_irqsave(&adapter->lock, flags);
+	
 	if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
 		/* send a "load multicast list" command to the board, max 10 addrs/cmd */
 		/* if num_addrs==0 the list will be cleared */
@@ -1291,9 +1255,13 @@
 	adapter->tx_pcb.length = 2;
 	adapter->got[CMD_CONFIGURE_82586] = 0;
 	if (!send_pcb(dev, &adapter->tx_pcb))
+	{
+		spin_unlock_irqrestore(&lp->lock, flags);
 		printk("%s: couldn't send 82586 configure command\n", dev->name);
+	}
 	else {
 		int timeout = jiffies + TIMEOUT;
+		spin_unlock_irqrestore(&lp->lock, flags);
 		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
 		if (time_after_eq(jiffies, timeout))
 			TIMEOUT_MSG(__LINE__);
@@ -1313,10 +1281,12 @@
 	/*
 	 * set ptrs to various functions
 	 */
-	dev->open = elp_open;	/* local */
-	dev->stop = elp_close;	/* local */
-	dev->get_stats = elp_get_stats;		/* local */
-	dev->hard_start_xmit = elp_start_xmit;	/* local */
+	dev->open = elp_open;				/* local */
+	dev->stop = elp_close;				/* local */
+	dev->get_stats = elp_get_stats;			/* local */
+	dev->hard_start_xmit = elp_start_xmit;		/* local */
+	dev->tx_timeout = elp_timeout;			/* local */
+	dev->watchdog_timeo = 10*HZ;
 	dev->set_multicast_list = elp_set_mc_list;	/* local */
 
 	/* Setup the generic properties */
diff -u --recursive --new-file v2.3.44/linux/drivers/net/3c505.h linux/drivers/net/3c505.h
--- v2.3.44/linux/drivers/net/3c505.h	Thu Aug 13 10:03:00 1998
+++ linux/drivers/net/3c505.h	Sun Feb 13 18:20:21 2000
@@ -289,4 +289,5 @@
 
 	unsigned int rx_active;  /* number of receive PCBs */
         volatile unsigned char hcr_val;  /* what we think the HCR contains */
+        spinlock_t lock;	/* Interrupt v tx lock */
 } elp_device;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.3.44/linux/drivers/net/3c59x.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/3c59x.c	Sun Feb 13 10:18:03 2000
@@ -403,8 +403,6 @@
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	struct net_device *next_module;
-	void *priv_addr;
-	dma_addr_t ring_dma;
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	struct net_device_stats stats;
@@ -769,13 +767,11 @@
 	vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn;
 	vp->pdev = pdev;
 
-	vp->priv_addr = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
-					     + sizeof(struct boom_tx_desc) * TX_RING_SIZE
-					     + 15, &vp->ring_dma);
-	/* Make sure rings are 16 byte aligned. */
-	vp->rx_ring = (void *)(((long)vp->priv_addr + 15) & ~15);
+	/* Makes sure rings are at least 16 byte aligned. */
+	vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
+					   + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
+					   &vp->rx_ring_dma);
 	vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
-	vp->rx_ring_dma = (vp->ring_dma + 15) & ~15;
 	vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
 
 	/* The lower four bits are the media type. */
@@ -2062,7 +2058,7 @@
 		kfree(root_vortex_dev);
 		pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
 					    + sizeof(struct boom_tx_desc) * TX_RING_SIZE
-					    + 15, vp->priv_addr, vp->ring_dma);
+					    + 15, vp->rx_ring, vp->rx_ring_dma);
 		kfree(vp);
 		root_vortex_dev = next_dev;
 	}
diff -u --recursive --new-file v2.3.44/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.3.44/linux/drivers/net/8139too.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/8139too.c	Sun Feb 13 10:23:26 2000
@@ -0,0 +1,1812 @@
+/*
+
+	8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
+
+	Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Originally: Written 1997-1999 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	Contributors:
+
+		Donald Becker - he wrote the original driver, kudos to him!
+		(but please don't e-mail him for support, this isn't his driver)
+
+		Tigran Aivazian - bug fixes, skbuff free cleanup
+
+		Martin Mares - suggestions for PCI cleanup
+		
+		David S. Miller - PCI DMA and softnet updates
+
+-----------------------------------------------------------------------------
+
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the RealTek RTL8139 series, the RealTek
+Fast Ethernet controllers for PCI and CardBus.  This chip is used on many
+low-end boards, sometimes with its markings changed.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+
+III. Driver operation
+
+IIIa. Rx Ring buffers
+
+The receive unit uses a single linear ring buffer rather than the more
+common (and more efficient) descriptor-based architecture.  Incoming frames
+are sequentially stored into the Rx region, and the host copies them into
+skbuffs.
+
+Comment: While it is theoretically possible to process many frames in place,
+any delay in Rx processing would cause us to drop frames.  More importantly,
+the Linux protocol stack is not designed to operate in this manner.
+
+IIIb. Tx operation
+
+The RTL8139 uses a fixed set of four Tx descriptors in register space.
+In a stunningly bad design choice, Tx frames must be 32 bit aligned.  Linux
+aligns the IP header on word boundaries, and 14 byte ethernet header means
+that almost all frames will need to be copied to an alignment buffer.
+
+IVb. References
+
+http://www.realtek.com.tw/cn/cn.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+1) The RTL-8139 has a serious problem with motherboards which do
+posted MMIO writes to PCI space.  This driver works around the
+problem by having an MMIO  register write be immediately followed by
+an MMIO register read.
+
+2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver.
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/io.h>
+
+
+#define RTL8139_VERSION "0.9.0"
+#define RTL8139_MODULE_NAME "8139too"
+#define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
+#define PFX RTL8139_MODULE_NAME ": "
+
+#undef RTL8139_DEBUG /* define to 1 to enable copious debugging info */
+
+#ifdef RTL8139_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define RTL8139_NDEBUG 0	/* define to 1 to disable lightweight runtime checks */
+#if RTL8139_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(!(expr)) {					\
+        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
+        #expr,__FILE__,__FUNCTION__,__LINE__);		\
+        }
+#endif
+
+#define arraysize(x)            (sizeof(x)/sizeof(*(x)))
+
+
+#ifndef PCI_GET_DRIVER_DATA
+  #define PCI_GET_DRIVER_DATA(pdev)		((pdev)->driver_data)
+  #define PCI_SET_DRIVER_DATA(pdev,data)	(((pdev)->driver_data) = (data))
+#endif /* PCI_GET_DRIVER_DATA */
+
+
+/* A few user-configurable values. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX	2	/* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE	1536
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
+#define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST	4	/* Calculate as 16<<val. */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (6*HZ)
+
+
+enum {
+	HAS_CHIP_XCVR = 0x020000,
+	HAS_LNK_CHNG = 0x040000,
+};
+
+#define RTL_IO_SIZE 256
+
+#define RTL8139_CAPS  HAS_CHIP_XCVR|HAS_LNK_CHNG
+
+typedef enum {
+	UNKNOWN = 0,
+	RTL8139,
+	RTL8139_CB,
+	SMC1211TX,
+	MPX5030,
+	SIS900,
+	SIS7016,
+} chip_t;
+
+static struct {
+	chip_t chip;
+	const char *name;
+} chip_info[] __devinitdata = {
+	{ RTL8139, "RealTek RTL8139 Fast Ethernet"},
+	{ RTL8139_CB, "RealTek RTL8139B PCI/CardBus"},
+	{ SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"},
+	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)"},
+	{ SIS900, "SiS 900 (RealTek RTL8139) Fast Ethernet"},
+	{ SIS7016, "SiS 7016 (RealTek RTL8139) Fast Ethernet"},
+	{0,},
+};
+
+static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {
+	{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+	{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB },
+	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
+	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },
+	{0x1039, 0x0900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS900 },
+	{0x1039, 0x7016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS7016 },
+	{0,},
+};
+MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
+
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC	4	/* Number of Tx descriptor registers. */
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+	MAC0 = 0,		/* Ethernet hardware address. */
+	MAR0 = 8,		/* Multicast filter. */
+	TxStatus0 = 0x10,	/* Transmit status (Four 32bit registers). */
+	TxAddr0 = 0x20,		/* Tx descriptors (also four 32bit). */
+	RxBuf = 0x30,
+	RxEarlyCnt = 0x34,
+	RxEarlyStatus = 0x36,
+	ChipCmd = 0x37,
+	RxBufPtr = 0x38,
+	RxBufAddr = 0x3A,
+	IntrMask = 0x3C,
+	IntrStatus = 0x3E,
+	TxConfig = 0x40,
+	RxConfig = 0x44,
+	Timer = 0x48,		/* A general-purpose counter. */
+	RxMissed = 0x4C,	/* 24 bits valid, write clears. */
+	Cfg9346 = 0x50,
+	Config0 = 0x51,
+	Config1 = 0x52,
+	FlashReg = 0x54,
+	GPPinData = 0x58,
+	GPPinDir = 0x59,
+	Config4 = 0x5A,		/* absent on RTL-8139A */
+	HltClk = 0x5B,
+	MultiIntr = 0x5C,
+	TxSummary = 0x60,
+	BasicModeCtrl = 0x62,
+	BasicModeStatus = 0x64,
+	NWayAdvert = 0x66,
+	NWayLPAR = 0x68,
+	NWayExpansion = 0x6A,
+	/* Undocumented registers, but required for proper operation. */
+	FIFOTMS = 0x70,		/* FIFO Control and test. */
+	CSCR = 0x74,		/* Chip Status and Configuration Register. */
+	PARA78 = 0x78,
+	PARA7c = 0x7c,		/* Magic transceiver parameter register. */
+};
+
+enum ChipCmdBits {
+	CmdReset = 0x10,
+	CmdRxEnb = 0x08,
+	CmdTxEnb = 0x04,
+	RxBufEmpty = 0x01,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+	PCIErr = 0x8000,
+	PCSTimeout = 0x4000,
+	RxFIFOOver = 0x40,
+	RxUnderrun = 0x20,
+	RxOverflow = 0x10,
+	TxErr = 0x08,
+	TxOK = 0x04,
+	RxErr = 0x02,
+	RxOK = 0x01,
+};
+enum TxStatusBits {
+	TxHostOwns = 0x2000,
+	TxUnderrun = 0x4000,
+	TxStatOK = 0x8000,
+	TxOutOfWindow = 0x20000000,
+	TxAborted = 0x40000000,
+	TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+	RxMulticast = 0x8000,
+	RxPhysical = 0x4000,
+	RxBroadcast = 0x2000,
+	RxBadSymbol = 0x0020,
+	RxRunt = 0x0010,
+	RxTooLong = 0x0008,
+	RxCRCErr = 0x0004,
+	RxBadAlign = 0x0002,
+	RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+	AcceptErr = 0x20,
+	AcceptRunt = 0x10,
+	AcceptBroadcast = 0x08,
+	AcceptMulticast = 0x04,
+	AcceptMyPhys = 0x02,
+	AcceptAllPhys = 0x01,
+};
+
+/* Bits in Config1 */
+enum Config1Bits {
+	Cfg1_PM_Enable = 0x01,
+	Cfg1_VPD_Enable = 0x02,
+	Cfg1_PIO = 0x04,
+	Cfg1_MMIO = 0x08,
+	Cfg1_LWAKE = 0x10,
+	Cfg1_Driver_Load = 0x20,
+	Cfg1_LED0 = 0x40,
+	Cfg1_LED1 = 0x80,
+};
+
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links. */
+enum CSCRBits {
+	CSCR_LinkOKBit = 0x0400,
+	CSCR_LinkChangeBit = 0x0800,
+	CSCR_LinkStatusBits = 0x0f000,
+	CSCR_LinkDownOffCmd = 0x003c0,
+	CSCR_LinkDownCmd = 0x0f3c0,
+};
+#define PARA78_default	0x78fa8388
+#define PARA7c_default	0xcb38de43	/* param[0][3] */
+#define PARA7c_xxx		0xcb38de43
+unsigned long param[4][4] = {
+	{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},
+	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},
+	{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}
+};
+
+struct ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+};
+
+
+#define PRIV_ALIGN	15	/* Required alignment mask */
+struct rtl8139_private {
+	chip_t chip;
+	void *mmio_addr;
+	spinlock_t lock;
+	int drv_flags;
+	struct pci_dev *pci_dev;
+	struct net_device_stats stats;
+	struct timer_list timer;	/* Media selection timer. */
+	unsigned char *rx_ring;
+	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
+	unsigned int rx_config;
+	unsigned int cur_tx, dirty_tx, tx_flag;
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct ring_info tx_info[NUM_TX_DESC];
+	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
+	unsigned char *tx_bufs;	/* Tx bounce buffer region. */
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_bufs_dma;
+	char phys[4];		/* MII device addresses. */
+	char twistie, twist_row, twist_col;	/* Twister tune state. */
+	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
+	unsigned int duplex_lock:1;
+	unsigned int default_port:4;	/* Last dev->if_port value. */
+	unsigned int media2:4;	/* Secondary monitored media port. */
+	unsigned int medialock:1;	/* Don't sense media type. */
+	unsigned int mediasense:1;	/* Media sensing in progress. */
+};
+
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
+MODULE_PARM (multicast_filter_limit, "i");
+MODULE_PARM (max_interrupt_work, "i");
+MODULE_PARM (debug, "i");
+
+static int read_eeprom (void *ioaddr, int location, int addr_len);
+static int rtl8139_open (struct net_device *dev);
+static int mdio_read (struct net_device *dev, int phy_id, int location);
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+			int val);
+static void rtl8139_timer (unsigned long data);
+static void rtl8139_tx_timeout (struct net_device *dev);
+static void rtl8139_init_ring (struct net_device *dev);
+static int rtl8139_start_xmit (struct sk_buff *skb,
+			       struct net_device *dev);
+static void rtl8139_interrupt (int irq, void *dev_instance,
+			       struct pt_regs *regs);
+static int rtl8139_close (struct net_device *dev);
+static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
+static inline u32 ether_crc (int length, unsigned char *data);
+static void rtl8139_set_rx_mode (struct net_device *dev);
+
+/* read after write, to avoid rtl8139 bug w/ posted MMIO writes */
+#define RTL_W8(reg, val8)	do { writeb (val8, ioaddr + reg); readb (ioaddr + reg); } while (0)
+#define RTL_W16(reg, val16)	do { writew (val16, ioaddr + reg); readw (ioaddr + reg); } while (0)
+#define RTL_W32(reg, val32)	do { writel (val32, ioaddr + reg); readl (ioaddr + reg); } while (0)
+#define RTL_R8(reg)		readb (ioaddr + reg)
+#define RTL_R16(reg)		readw (ioaddr + reg)
+#define RTL_R32(reg)		readl (ioaddr + reg)
+
+
+static const char * __devinit rtl8139_name_from_chip (chip_t chip)
+{
+	int i;
+	
+	for (i = 0; i < arraysize (chip_info); i++)
+		if (chip == chip_info[i].chip)
+			return chip_info[i].name;
+	
+	return "unknown";
+}
+
+
+static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
+{
+	void *ioaddr = NULL;
+	u8 tmp8;
+	int rc;
+	u32 pio_start, pio_end, pio_flags;
+	u32 mmio_start, mmio_end, mmio_flags;
+
+	DPRINTK ("ENTER\n");
+
+	assert (pdev != NULL);
+	assert (ioaddr_out != NULL);
+
+	*ioaddr_out = NULL;
+
+	pio_start = pci_resource_start (pdev, 0);
+	pio_end = pci_resource_end (pdev, 0);
+	pio_flags = pci_resource_flags (pdev, 0);
+
+	mmio_start = pci_resource_start (pdev, 1);
+	mmio_end = pci_resource_end (pdev, 1);
+	mmio_flags = pci_resource_flags (pdev, 1);
+
+	/* make sure PCI base addr 0 is PIO */
+	if (pio_start == 0 || pio_end <= pio_start ||
+	    (!(pio_flags & IORESOURCE_IO))) {
+		printk (KERN_ERR PFX "no PIO resource, aborting\n");
+		return -ENODEV;
+	}
+	
+	/* make sure PCI base addr 1 is MMIO */
+	if (mmio_start == 0 || mmio_end <= mmio_start ||
+	    (!(mmio_flags & IORESOURCE_MEM))) {
+		printk (KERN_ERR PFX "no MMIO resource, aborting\n");
+		return -ENODEV;
+	}
+
+	/* make sure our PIO region in PCI space is available */
+	if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) {
+		printk (KERN_ERR PFX "no I/O resource available, aborting\n");
+		return -EBUSY;
+	}
+	
+	/* make sure our MMIO region in PCI space is available */
+	if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) {
+		release_region (pio_start, RTL_IO_SIZE);
+		printk (KERN_ERR PFX "no mem resource available, aborting\n");
+		return -EBUSY;
+	}
+	
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	pci_enable_device (pdev);
+	pci_set_master (pdev);
+
+	/* ioremap MMIO region */
+	ioaddr = ioremap (mmio_start, RTL_IO_SIZE);
+	if (ioaddr == NULL) {
+		printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out;
+	}
+
+	/* Bring the chip out of low-power mode. */
+	RTL_W8 (Config1, 0x00);
+
+	/* make sure chip thinks PIO and MMIO are enabled */
+	tmp8 = RTL_R8 (Config1);
+	if ((tmp8 & Cfg1_PIO) == 0) {
+		printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8);
+		rc = -EIO;
+		goto err_out;
+	}
+	if ((tmp8 & Cfg1_MMIO) == 0) {
+		printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8);
+		rc = -EIO;
+		goto err_out;
+	}
+	
+	/* sanity checks -- ensure PIO and MMIO registers agree */
+	assert (inb (pio_start+Config0) == RTL_R8 (Config0));
+	assert (inb (pio_start+Config1) == RTL_R8 (Config1));
+	assert (inb (pio_start+TxConfig) == RTL_R8 (TxConfig));
+	assert (inb (pio_start+RxConfig) == RTL_R8 (RxConfig));
+
+	DPRINTK ("EXIT, returning 0\n");
+	*ioaddr_out = ioaddr;
+	return 0;	
+
+err_out:
+	if (ioaddr)
+		iounmap (ioaddr);
+	release_region (pio_start, RTL_IO_SIZE);
+	release_mem_region (mmio_start, RTL_IO_SIZE);
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+
+static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct rtl8139_private *tp;
+	int i, addr_len, option = -1;
+	void *ioaddr = NULL;
+
+	DPRINTK ("ENTER\n");
+	
+	assert (pdev != NULL);
+	assert (ent != NULL);
+	
+	i = rtl8139_init_pci (pdev, &ioaddr);
+	if (i < 0) {
+		DPRINTK ("EXIT, returning %d\n", i);
+		return i;
+	}
+	
+	assert (ioaddr != NULL);
+
+	/* dev zeroed in init_etherdev */
+	dev = init_etherdev (NULL, sizeof (*tp) + PRIV_ALIGN);
+	if (dev == NULL) {
+		iounmap (ioaddr);
+		printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+		DPRINTK ("EXIT, returning -ENOMEM\n");
+		return -ENOMEM;
+	}
+
+	addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6;
+	for (i = 0; i < 3; i++)
+		((u16 *) (dev->dev_addr))[i] =
+		    le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+
+	/* The Rtl8139-specific entries in the device structure. */
+	dev->open = rtl8139_open;
+	dev->hard_start_xmit = rtl8139_start_xmit;
+	dev->stop = rtl8139_close;
+	dev->get_stats = rtl8139_get_stats;
+	dev->set_multicast_list = rtl8139_set_rx_mode;
+	dev->do_ioctl = mii_ioctl;
+	dev->tx_timeout = rtl8139_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	dev->irq = pdev->irq;
+	dev->base_addr = pci_resource_start (pdev, 1);
+
+	dev->priv = tp = (void *)
+		(((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
+
+	printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, "
+		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+		dev->name, rtl8139_name_from_chip(ent->driver_data),
+		dev->base_addr, dev->irq,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5]);
+
+	/* tp zeroed in init_etherdev */
+	tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER | RTL8139_CAPS;
+	tp->pci_dev = pdev;
+	tp->chip = ent->driver_data;
+	tp->mmio_addr = ioaddr;
+	tp->lock = SPIN_LOCK_UNLOCKED;
+
+	PCI_SET_DRIVER_DATA (pdev, dev);
+
+	tp->phys[0] = 32;
+
+	/* Put the chip into low-power mode. */
+	RTL_W8 (Cfg9346, 0xC0);
+	RTL_W8 (Config1, 0x03);	/* Enable PM & PCI VPD */
+	RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		tp->full_duplex = (option & 0x200) ? 1 : 0;
+		tp->default_port = option & 15;
+		if (tp->default_port)
+			tp->medialock = 1;
+	}
+
+	if (tp->full_duplex) {
+		printk (KERN_INFO
+			"%s: Media type forced to Full Duplex.\n",
+			dev->name);
+		mdio_write (dev, tp->phys[0], 4, 0x141);
+		tp->duplex_lock = 1;
+	}
+
+	DPRINTK ("EXIT - returning 0\n");
+	return 0;
+}
+
+
+static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
+	struct rtl8139_private *np;
+
+	DPRINTK ("ENTER\n");
+
+	assert (dev != NULL);
+
+	np = (struct rtl8139_private *) (dev->priv);
+	assert (np != NULL);
+
+	unregister_netdev (dev);
+
+	iounmap (np->mmio_addr);
+	release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE);
+	release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE);
+
+#ifndef RTL8139_NDEBUG
+	/* poison memory before freeing */
+	memset (dev, 0xC0,
+		sizeof (struct net_device) +
+		sizeof (struct rtl8139_private) +
+		PRIV_ALIGN);
+#endif
+
+	kfree (dev);
+	
+	DPRINTK ("EXIT\n");
+}
+
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x08	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x00
+#define EE_WRITE_1		0x02
+#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
+#define EE_ENB			(0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay()	readl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5)
+#define EE_READ_CMD		(6)
+#define EE_ERASE_CMD	(7)
+
+static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+{
+	int i;
+	unsigned retval = 0;
+	void *ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	DPRINTK ("ENTER\n");
+
+	writeb (EE_ENB & ~EE_CS, ee_addr);
+	writeb (EE_ENB, ee_addr);
+	eeprom_delay ();
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		writeb (EE_ENB | dataval, ee_addr);
+		eeprom_delay ();
+		writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay ();
+	}
+	writeb (EE_ENB, ee_addr);
+	eeprom_delay ();
+
+	for (i = 16; i > 0; i--) {
+		writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay ();
+		retval =
+		    (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
+				     0);
+		writeb (EE_ENB, ee_addr);
+		eeprom_delay ();
+	}
+
+	/* Terminate the EEPROM access. */
+	writeb (~EE_CS, ee_addr);
+	eeprom_delay ();
+
+	DPRINTK ("EXIT - returning %d\n", retval);
+	return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+   serial MDIO protocol.
+   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues. */
+#define MDIO_DIR		0x80
+#define MDIO_DATA_OUT	0x04
+#define MDIO_DATA_IN	0x02
+#define MDIO_CLK		0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay()	readb(mdio_addr)
+
+
+static char mii_2_8139_map[8] = {
+	BasicModeCtrl,
+	BasicModeStatus,
+	0,
+	0,
+	NWayAdvert,
+	NWayLPAR,
+	NWayExpansion,
+	0
+};
+
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync (void *mdio_addr)
+{
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	for (i = 32; i >= 0; i--) {
+		writeb (MDIO_WRITE1, mdio_addr);
+		mdio_delay ();
+		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
+		mdio_delay ();
+	}
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static int mdio_read (struct net_device *dev, int phy_id, int location)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *mdio_addr = tp->mmio_addr + Config4;
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int retval = 0;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		DPRINTK ("EXIT after directly using 8139 internal regs\n");
+		return location < 8 && mii_2_8139_map[location] ?
+		    readw (tp->mmio_addr + mii_2_8139_map[location]) : 0;
+	}
+	mdio_sync (mdio_addr);
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+		writeb (MDIO_DIR | dataval, mdio_addr);
+		mdio_delay ();
+		writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+		mdio_delay ();
+	}
+
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		writeb (0, mdio_addr);
+		mdio_delay ();
+		retval =
+		    (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1
+				     : 0);
+		writeb (MDIO_CLK, mdio_addr);
+		mdio_delay ();
+	}
+
+	DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff);
+	return (retval >> 1) & 0xffff;
+}
+
+
+static void mdio_write (struct net_device *dev, int phy_id, int location,
+			int value)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *mdio_addr = tp->mmio_addr + Config4;
+	int mii_cmd =
+	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		if (location < 8 && mii_2_8139_map[location]) {
+			writew (value,
+				tp->mmio_addr + mii_2_8139_map[location]);
+			readw (tp->mmio_addr + mii_2_8139_map[location]);
+		}
+		DPRINTK ("EXIT after directly using 8139 internal regs\n");
+		return;
+	}
+	mdio_sync (mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval =
+		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+		writeb (dataval, mdio_addr);
+		mdio_delay ();
+		writeb (dataval | MDIO_CLK, mdio_addr);
+		mdio_delay ();
+	}
+
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		writeb (0, mdio_addr);
+		mdio_delay ();
+		writeb (MDIO_CLK, mdio_addr);
+		mdio_delay ();
+	}
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static int rtl8139_open (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	MOD_INC_USE_COUNT;
+
+	/* Soft reset the chip. */
+	RTL_W8 (ChipCmd, CmdReset);
+
+	if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) {
+		DPRINTK ("EXIT, returning -EBUSY\n");
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
+
+	tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+					   &tp->tx_bufs_dma);
+	tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+					   &tp->rx_ring_dma);
+	if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
+		free_irq(dev->irq, dev);
+
+		if (tp->tx_bufs)
+			pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+					    tp->tx_bufs, tp->tx_bufs_dma);
+		if (tp->rx_ring)
+			pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+					    tp->rx_ring, tp->rx_ring_dma);
+
+		DPRINTK ("EXIT, returning -ENOMEM\n");
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+		
+	}
+	
+	rtl8139_init_ring (dev);
+	tp->full_duplex = tp->duplex_lock;
+	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+	tp->rx_config =
+	    (RX_FIFO_THRESH << 13) |
+	    (RX_BUF_LEN_IDX << 11) |
+	    (RX_DMA_BURST << 8);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+			break;
+
+	RTL_W32 (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+	RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+	RTL_W32 (RxConfig, tp->rx_config);
+	RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
+
+	/* Reset N-Way to chipset defaults */
+	RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
+			break;
+	
+	/* Set N-Way to sane defaults */
+	RTL_W16 (FIFOTMS, 0x0000);
+	RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
+	RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
+	
+	RTL_W8 (Cfg9346, 0xC0);
+	RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+	RTL_W8 (Cfg9346, 0x00);
+
+	RTL_W32 (RxBuf, tp->rx_ring_dma);
+
+	/* Start the chip's Tx and Rx process. */
+	RTL_W32 (RxMissed, 0);
+	rtl8139_set_rx_mode (dev);
+
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
+	/* Enable all known interrupts by setting the interrupt mask. */
+	RTL_W16 (IntrMask,
+		 PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		 | TxErr | TxOK | RxErr | RxOK);
+
+	DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d"
+			" GP Pins %2.2x %s-duplex.\n",
+			dev->name, pci_resource_start (tp->pci_dev, 1),
+			dev->irq, RTL_R8 (GPPinData),
+			tp->full_duplex ? "full" : "half");
+
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer (&tp->timer);
+	tp->timer.expires = jiffies + 3 * HZ;
+	tp->timer.data = (unsigned long) dev;
+	tp->timer.function = &rtl8139_timer;
+	add_timer (&tp->timer);
+
+	netif_start_queue (dev);
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+/* Start the hardware at open or resume. */
+static void rtl8139_hw_start (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	/* Soft reset the chip. */
+	RTL_W8 (ChipCmd, CmdReset);
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
+			break;
+
+	/* Restore our idea of the MAC address. */
+	RTL_W32 (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+	RTL_W32 (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+	/* Hmmm, do these belong here? */
+	RTL_W8 (Cfg9346, 0x00);
+	tp->cur_rx = 0;
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+	RTL_W32 (RxConfig, tp->rx_config);
+	/* Check this value: the documentation contradicts ifself.  Is the
+	   IFG correct with bit 28:27 zero, or with |0x03000000 ? */
+	RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
+
+	/* Reset N-Way to chipset defaults */
+	RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
+			break;
+	
+	/* Set N-Way to sane defaults */
+	RTL_W16 (FIFOTMS, 0x0000);
+	RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
+	RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
+	
+	/* check_duplex() here. */
+	RTL_W8 (Cfg9346, 0xC0);
+	RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+	RTL_W8 (Cfg9346, 0x00);
+
+	RTL_W32 (RxBuf, tp->rx_ring_dma);
+	/* Start the chip's Tx and Rx process. */
+	RTL_W32 (RxMissed, 0);
+	rtl8139_set_rx_mode (dev);
+	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+	/* Enable all known interrupts by setting the interrupt mask. */
+	RTL_W16 (IntrMask,
+		 PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		 | TxErr | TxOK | RxErr | RxOK);
+
+	netif_start_queue (dev);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+#ifndef RTL_TUNE_TWISTER
+static inline void rtl8139_tune_twister (struct net_device *dev,
+				  struct rtl8139_private *tp) {}
+#else
+static void rtl8139_tune_twister (struct net_device *dev,
+				  struct rtl8139_private *tp)
+{
+	int linkcase;
+
+	DPRINTK ("ENTER\n");
+
+	/* This is a complicated state machine to configure the "twister" for
+	   impedance/echos based on the cable length.
+	   All of this is magic and undocumented.
+	 */
+	switch (tp->twistie) {
+	case 1:
+		if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {
+			/* We have link beat, let us tune the twister. */
+			RTL_W16 (CSCR, CSCR_LinkDownOffCmd);
+			tp->twistie = 2;	/* Change to state 2. */
+			next_tick = HZ / 10;
+		} else {
+			/* Just put in some reasonable defaults for when beat returns. */
+			RTL_W16 (CSCR, CSCR_LinkDownCmd);
+			RTL_W32 (FIFOTMS, 0x20);	/* Turn on cable test mode. */
+			RTL_W32 (PARA78, PARA78_default);
+			RTL_W32 (PARA7c, PARA7c_default);
+			tp->twistie = 0;	/* Bail from future actions. */
+		}
+		break;
+	case 2:
+		/* Read how long it took to hear the echo. */
+		linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;
+		if (linkcase == 0x7000)
+			tp->twist_row = 3;
+		else if (linkcase == 0x3000)
+			tp->twist_row = 2;
+		else if (linkcase == 0x1000)
+			tp->twist_row = 1;
+		else
+			tp->twist_row = 0;
+		tp->twist_col = 0;
+		tp->twistie = 3;	/* Change to state 2. */
+		next_tick = HZ / 10;
+		break;
+	case 3:
+		/* Put out four tuning parameters, one per 100msec. */
+		if (tp->twist_col == 0)
+			RTL_W16 (FIFOTMS, 0);
+		RTL_W32 (PARA7c, param[(int) tp->twist_row]
+			 [(int) tp->twist_col]);
+		next_tick = HZ / 10;
+		if (++tp->twist_col >= 4) {
+			/* For short cables we are done.
+			   For long cables (row == 3) check for mistune. */
+			tp->twistie =
+			    (tp->twist_row == 3) ? 4 : 0;
+		}
+		break;
+	case 4:
+		/* Special case for long cables: check for mistune. */
+		if ((RTL_R16 (CSCR) &
+		     CSCR_LinkStatusBits) == 0x7000) {
+			tp->twistie = 0;
+			break;
+		} else {
+			RTL_W32 (PARA7c, 0xfb38de03);
+			tp->twistie = 5;
+			next_tick = HZ / 10;
+		}
+		break;
+	case 5:
+		/* Retune for shorter cable (column 2). */
+		RTL_W32 (FIFOTMS, 0x20);
+		RTL_W32 (PARA78, PARA78_default);
+		RTL_W32 (PARA7c, PARA7c_default);
+		RTL_W32 (FIFOTMS, 0x00);
+		tp->twist_row = 2;
+		tp->twist_col = 0;
+		tp->twistie = 3;
+		next_tick = HZ / 10;
+		break;
+
+	default:
+		/* do nothing */
+		break;
+	}
+
+	DPRINTK ("EXIT\n");
+}
+#endif /* RTL_TUNE_TWISTER */
+
+
+static void rtl8139_timer (unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int next_tick = 60 * HZ;
+	int mii_reg5 = mdio_read (dev, tp->phys[0], 5);
+
+	DPRINTK ("ENTER\n");
+
+	if (!tp->duplex_lock && mii_reg5 != 0xffff) {
+		int duplex = (mii_reg5 & 0x0100)
+		    || (mii_reg5 & 0x01C0) == 0x0040;
+		if (tp->full_duplex != duplex) {
+			tp->full_duplex = duplex;
+			printk (KERN_INFO
+				"%s: Setting %s-duplex based on MII #%d link"
+				" partner ability of %4.4x.\n", dev->name,
+				tp->full_duplex ? "full" : "half",
+				tp->phys[0], mii_reg5);
+			RTL_W8 (Cfg9346, 0xC0);
+			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Cfg9346, 0x00);
+		}
+	}
+
+	rtl8139_tune_twister (dev, tp);
+
+	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
+		 dev->name, RTL_R16 (NWayLPAR));
+	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
+		 " RxStatus %4.4x.\n", dev->name,
+		 RTL_R16 (IntrMask),
+		 RTL_R16 (IntrStatus),
+		 RTL_R32 (RxEarlyStatus));
+	DPRINTK ("%s:  Chip config %2.2x %2.2x.\n",
+		 dev->name, RTL_R8 (Config0),
+		 RTL_R8 (Config1));
+
+	tp->timer.expires = jiffies + next_tick;
+	add_timer (&tp->timer);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static void rtl8139_tx_timeout (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int mii_reg, i;
+
+	DPRINTK ("ENTER\n");
+
+	netif_stop_queue (dev);
+
+	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
+		 "media %2.2x.\n", dev->name,
+		 readb (ioaddr + ChipCmd),
+		 readw (ioaddr + IntrStatus),
+		 readb (ioaddr + GPPinData));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16 (IntrMask, 0x0000);
+	/* Emit info to figure out what went wrong. */
+	printk (KERN_DEBUG
+		"%s: Tx queue start entry %d  dirty entry %d.\n",
+		dev->name, tp->cur_tx, tp->dirty_tx);
+	for (i = 0; i < NUM_TX_DESC; i++)
+		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8x.%s\n",
+			dev->name, i, readl (ioaddr + TxStatus0 + i * 4),
+			i ==
+		      tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
+	printk (KERN_DEBUG "%s: MII #%d registers are:", dev->name,
+		tp->phys[0]);
+	for (mii_reg = 0; mii_reg < 8; mii_reg++)
+		printk (" %4.4x", mdio_read (dev, tp->phys[0], mii_reg));
+	printk (".\n");
+
+	/* Stop a shared interrupt from scavenging while we are. */
+	tp->dirty_tx = tp->cur_tx = 0;
+
+	/* Dump the unsent Tx packets. */
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		struct ring_info *rp = &tp->tx_info[i];
+		if (rp->skb) {
+			dev_kfree_skb (rp->skb);
+			rp->skb = NULL;
+			tp->stats.tx_dropped++;
+		}
+		if (rp->mapping != 0) {
+			pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len);
+			rp->mapping = 0;
+		}
+	}
+
+	rtl8139_hw_start (dev);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	tp->cur_rx = 0;
+	tp->dirty_tx = tp->cur_tx = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tp->tx_info[i].skb = NULL;
+		tp->tx_info[i].mapping = 0;
+		tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE];
+	}
+
+	DPRINTK ("EXIT\n");
+}
+
+static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int entry;
+	unsigned long flags;
+
+	DPRINTK ("ENTER\n");
+	
+	netif_stop_queue (dev);
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % NUM_TX_DESC;
+
+	spin_lock_irqsave (&tp->lock, flags);
+	
+	tp->tx_info[entry].skb = skb;
+	if ((long) skb->data & 3) {	/* Must use alignment buffer. */
+		tp->tx_info[entry].mapping = 0;
+		memcpy (tp->tx_buf[entry], skb->data, skb->len);
+
+		assert (tp->tx_bufs_dma > 0);
+		RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
+	} else {
+		tp->tx_info[entry].mapping =
+			pci_map_single(tp->pci_dev, skb->data, skb->len);
+
+		assert (tp->tx_info[entry].mapping > 0);
+		RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping);
+	}
+	
+	/* Note: the chip doesn't have auto-pad! */
+	RTL_W32 (TxStatus0 + entry * 4,
+		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+
+	dev->trans_start = jiffies;
+	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC)	/* Typical path */
+		netif_start_queue (dev);
+
+	spin_unlock_irqrestore (&tp->lock, flags);
+	
+	DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n",
+		 dev->name, skb->data, skb->len, entry);
+
+	DPRINTK ("EXIT\n");
+	return 0;
+}
+
+
+static inline void rtl8139_tx_interrupt (struct net_device *dev,
+					 struct rtl8139_private *tp)
+{
+	void *ioaddr;
+	unsigned int dirty_tx;
+
+	assert (dev != NULL);
+	assert (tp != NULL);
+
+	dirty_tx = tp->dirty_tx;
+	ioaddr = tp->mmio_addr;
+
+	while (tp->cur_tx - dirty_tx > 0) {
+		int entry = dirty_tx % NUM_TX_DESC;
+		int txstatus = readl (ioaddr + TxStatus0 + entry * 4);
+
+		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+			break;	/* It still hasn't been Txed */
+
+		/* Note: TxCarrierLost is always asserted at 100mbps. */
+		if (txstatus & (TxOutOfWindow | TxAborted)) {
+			/* There was an major error, log it. */
+			DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
+				 dev->name, txstatus);
+			tp->stats.tx_errors++;
+			if (txstatus & TxAborted) {
+				tp->stats.tx_aborted_errors++;
+				RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x03000001);
+			}
+			if (txstatus & TxCarrierLost)
+				tp->stats.tx_carrier_errors++;
+			if (txstatus & TxOutOfWindow)
+				tp->stats.tx_window_errors++;
+#ifdef ETHER_STATS
+			if ((txstatus & 0x0f000000) == 0x0f000000)
+				tp->stats.collisions16++;
+#endif
+		} else {
+			if (txstatus & TxUnderrun) {
+				/* Add 64 to the Tx FIFO threshold. */
+				if (tp->tx_flag < 0x00300000)
+					tp->tx_flag += 0x00020000;
+				tp->stats.tx_fifo_errors++;
+			}
+			tp->stats.collisions += (txstatus >> 24) & 15;
+			tp->stats.tx_bytes += txstatus & 0x7ff;
+			tp->stats.tx_packets++;
+		}
+
+		if (tp->tx_info[entry].mapping != 0) {
+			pci_unmap_single (tp->pci_dev,
+					  tp->tx_info[entry].mapping,
+					  tp->tx_info[entry].skb->len);
+			tp->tx_info[entry].mapping = 0;
+		}
+		/* Free the original skb. */
+		dev_kfree_skb_irq (tp->tx_info[entry].skb);
+		tp->tx_info[entry].skb = NULL;
+		dirty_tx++;
+		if (tp->cur_tx - dirty_tx < NUM_TX_DESC)
+			netif_wake_queue (dev);
+		else
+			netif_stop_queue (dev);
+	}
+
+#ifndef RTL8139_NDEBUG
+	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+		printk (KERN_ERR
+		  "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
+		     dev->name, dirty_tx, tp->cur_tx);
+		dirty_tx += NUM_TX_DESC;
+	}
+#endif
+
+	tp->dirty_tx = dirty_tx;
+}
+
+
+/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
+   field alignments and semantics. */
+static inline void rtl8139_rx_interrupt (struct net_device *dev,
+					 struct rtl8139_private *tp)
+{
+	void *ioaddr = tp->mmio_addr;
+	unsigned char *rx_ring = tp->rx_ring;
+	u16 cur_rx = tp->cur_rx;
+
+	DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+			" free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+			readw (ioaddr + RxBufAddr),
+			readw (ioaddr + RxBufPtr),
+			readb (ioaddr + ChipCmd));
+
+	while ((readb (ioaddr + ChipCmd) & RxBufEmpty) == 0) {
+		int ring_offset = cur_rx % RX_BUF_LEN;
+		u32 rx_status =
+		    le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+		int rx_size = rx_status >> 16;
+
+#ifdef RTL8139_DEBUG
+		int i;
+		DPRINTK ("%s:  rtl8139_rx() status %4.4x, size %4.4x,"
+			" cur %4.4x.\n", dev->name, rx_status,
+			rx_size, cur_rx);
+		DPRINTK ("%s: Frame contents ", dev->name);
+		for (i = 0; i < 70; i++)
+			printk (" %2.2x", rx_ring[ring_offset + i]);
+		printk (".\n");
+#endif
+
+		if (rx_status &
+		    (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr |
+		     RxBadAlign)) {
+			DPRINTK ("%s: Ethernet frame had errors,"
+					" status %8.8x.\n", dev->name,
+					rx_status);
+			if (rx_status & RxTooLong) {
+				DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
+						dev->name, rx_status);
+				/* A.C.: The chip hangs here. */
+			}
+			tp->stats.rx_errors++;
+			if (rx_status & (RxBadSymbol | RxBadAlign))
+				tp->stats.rx_frame_errors++;
+			if (rx_status & (RxRunt | RxTooLong))
+				tp->stats.rx_length_errors++;
+			if (rx_status & RxCRCErr)
+				tp->stats.rx_crc_errors++;
+			/* Reset the receiver, based on RealTek recommendation. (Bug?) */
+			tp->cur_rx = 0;
+			RTL_W8 (ChipCmd, CmdTxEnb);
+			/* A.C.: Reset the multicast list. */
+			rtl8139_set_rx_mode (dev);
+			RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
+			/* Omit the four octet CRC from the length. */
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb (rx_size + 2);
+			if (skb == NULL) {
+				printk (KERN_WARNING
+					"%s: Memory squeeze, deferring packet.\n",
+					dev->name);
+				/* We should check that some rx space is free.
+				   If not, free one and mark stats->rx_dropped++. */
+				tp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
+			if (ring_offset + rx_size + 4 > RX_BUF_LEN) {
+				int semi_count =
+				    RX_BUF_LEN - ring_offset - 4;
+				/* This could presumably use two calls to copy_and_sum()? */
+				memcpy (skb_put (skb, semi_count),
+					&rx_ring[ring_offset + 4],
+					semi_count);
+				memcpy (skb_put
+					(skb, rx_size - semi_count),
+					rx_ring, rx_size - semi_count);
+#ifdef RTL8139_DEBUG
+				{
+				int i;
+				printk (KERN_DEBUG
+					"%s:  Frame wrap @%d",
+					dev->name, semi_count);
+				for (i = 0; i < 16; i++)
+					printk (" %2.2x",
+						rx_ring[i]);
+				printk (".\n");
+				memset (rx_ring, 0xcc, 16);
+				}
+#endif /* RTL8139_DEBUG */
+
+			} else {
+				eth_copy_and_sum (skb,
+						  &rx_ring[ring_offset +
+							   4], rx_size, 0);
+				skb_put (skb, rx_size);
+			}
+			skb->protocol = eth_type_trans (skb, dev);
+			netif_rx (skb);
+			tp->stats.rx_bytes += rx_size;
+			tp->stats.rx_packets++;
+		}
+
+		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+		RTL_W16 (RxBufPtr, cur_rx - 16);
+	}
+	DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
+		" free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
+		readw (ioaddr + RxBufAddr),
+		readw (ioaddr + RxBufPtr),
+		readb (ioaddr + ChipCmd));
+	tp->cur_rx = cur_rx;
+}
+
+
+static inline int rtl8139_weird_interrupt (struct net_device *dev,
+					   struct rtl8139_private *tp,
+					   int status, int link_changed)
+{
+	void *ioaddr;
+
+	DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+		 dev->name, status);
+		 
+	assert (dev != NULL);
+	assert (tp != NULL);
+
+	ioaddr = tp->mmio_addr;
+
+	if (status == 0xffffffff) {
+		printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n");
+		return -1;
+	}
+
+	/* Update the error count. */
+	tp->stats.rx_missed_errors +=
+	    readl (ioaddr + RxMissed);
+	RTL_W32 (RxMissed, 0);
+
+	if ((status & RxUnderrun) && link_changed &&
+	    (tp->drv_flags & HAS_LNK_CHNG)) {
+		/* Really link-change on new chips. */
+		int lpar = readw (ioaddr + NWayLPAR);
+		int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040
+				|| tp->duplex_lock;
+		if (tp->full_duplex != duplex) {
+			tp->full_duplex = duplex;
+			RTL_W8 (Cfg9346, 0xC0);
+			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Cfg9346, 0x00);
+		}
+		status &= ~RxUnderrun;
+	}
+	if (status &
+	    (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+		tp->stats.rx_errors++;
+
+	if (status & (PCSTimeout))
+		tp->stats.rx_length_errors++;
+	if (status & (RxUnderrun | RxFIFOOver))
+		tp->stats.rx_fifo_errors++;
+	if (status & RxOverflow) {
+		tp->stats.rx_over_errors++;
+		tp->cur_rx = readw (ioaddr + RxBufAddr) % RX_BUF_LEN;
+		RTL_W16 (RxBufPtr, tp->cur_rx - 16);
+	}
+	if (status & PCIErr) {
+		u16 pci_cmd_status;
+		pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
+
+		printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
+			dev->name, pci_cmd_status);
+	}
+	
+	return 0;
+}
+
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void rtl8139_interrupt (int irq, void *dev_instance,
+			       struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	int boguscnt = max_interrupt_work;
+	void *ioaddr = tp->mmio_addr;
+	int link_changed = 0;	/* Grrr, avoid bogus "uninitialized" warning */
+
+	spin_lock_irq (&tp->lock);
+
+	do {
+		int status = readw (ioaddr + IntrStatus);
+		/* Acknowledge all of the current interrupt sources ASAP, but
+		   an first get an additional status bit from CSCR. */
+		if (status & RxUnderrun)
+			link_changed = readw (ioaddr + CSCR) & CSCR_LinkChangeBit;
+		RTL_W16 (IntrStatus, status);
+
+		DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
+				dev->name, status,
+				readw (ioaddr + IntrStatus));
+
+		if ((status &
+		     (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
+		      RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
+			break;
+
+		/* Check uncommon events with one test. */
+		if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
+		  	      RxFIFOOver | TxErr | RxErr))
+			if (rtl8139_weird_interrupt (dev, tp, status,
+						     link_changed) == -1)
+				break;
+
+		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
+			rtl8139_rx_interrupt (dev, tp);
+
+		if (status & (TxOK | TxErr))
+			rtl8139_tx_interrupt (dev, tp);
+
+		if (--boguscnt < 0) {
+			printk (KERN_WARNING
+				"%s: Too much work at interrupt, "
+				"IntrStatus=0x%4.4x.\n", dev->name,
+				status);
+			/* Clear all interrupt sources. */
+			RTL_W16 (IntrStatus, 0xffff);
+			break;
+		}
+	} while (1);
+
+	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
+			dev->name, readw (ioaddr + IntrStatus));
+
+	spin_unlock_irq (&tp->lock);
+	return;
+}
+
+static int rtl8139_close (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i;
+
+	DPRINTK ("ENTER\n");
+
+	netif_stop_queue (dev);
+
+	DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
+			dev->name, readw (ioaddr + IntrStatus));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16 (IntrMask, 0x0000);
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	RTL_W8 (ChipCmd, 0x00);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+	RTL_W32 (RxMissed, 0);
+
+	del_timer (&tp->timer);
+
+	free_irq (dev->irq, dev);
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		struct sk_buff *skb = tp->tx_info[i].skb;
+		dma_addr_t mapping = tp->tx_info[i].mapping;
+
+		if (skb) {
+			if (mapping)
+				pci_unmap_single (tp->pci_dev, mapping, skb->len);
+			dev_kfree_skb (skb);
+		}
+		tp->tx_info[i].skb = NULL;
+		tp->tx_info[i].mapping = 0;
+	}
+
+	pci_free_consistent(tp->pci_dev, RX_BUF_LEN + 16,
+			    tp->rx_ring, tp->rx_ring_dma);
+	pci_free_consistent(tp->pci_dev, TX_BUF_SIZE * NUM_TX_DESC,
+			    tp->tx_bufs, tp->tx_bufs_dma);
+	tp->rx_ring = NULL;
+	tp->tx_bufs = NULL;
+
+	/* Green! Put the chip in low-power mode. */
+	RTL_W8 (Cfg9346, 0xC0);
+	RTL_W8 (Config1, 0x03);
+	RTL_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+
+	MOD_DEC_USE_COUNT;
+
+	DPRINTK ("EXIT\n");
+	return 0;
+}
+
+static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	u16 *data = (u16 *) & rq->ifr_data;
+
+	DPRINTK ("ENTER\n");
+
+	switch (cmd) {
+	case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
+		data[0] = tp->phys[0] & 0x3f;
+		/* Fall Through */
+	case SIOCDEVPRIVATE + 1:	/* Read the specified MII register. */
+		data[3] = mdio_read (dev, data[0], data[1] & 0x1f);
+		DPRINTK ("EXIT\n");
+		return 0;
+	case SIOCDEVPRIVATE + 2:	/* Write the specified MII register */
+		if (!capable (CAP_NET_ADMIN))
+			return -EPERM;
+		mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
+		DPRINTK ("EXIT\n");
+		return 0;
+	default:
+		DPRINTK ("EXIT\n");
+		return -EOPNOTSUPP;
+	}
+
+	DPRINTK ("EXIT\n");
+}
+
+static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+
+	DPRINTK ("ENTER\n");
+
+	assert (tp != NULL);
+
+	if (test_bit(LINK_STATE_START, &dev->state)) {
+		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+		RTL_W32 (RxMissed, 0);
+	}
+
+	DPRINTK ("EXIT\n");
+	return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   This routine is not state sensitive and need not be SMP locked. */
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc (int length, unsigned char *data)
+{
+	int crc = -1;
+
+	DPRINTK ("ENTER\n");
+
+	while (--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^
+			    ((crc < 0) ^ (current_octet & 1) ?
+			     ethernet_polynomial : 0);
+	}
+
+	DPRINTK ("EXIT\n");
+	return crc;
+}
+
+static void rtl8139_set_rx_mode (struct net_device *dev)
+{
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int i, rx_mode;
+
+	DPRINTK ("ENTER\n");
+
+	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+			dev->name, dev->flags, readl (ioaddr + RxConfig));
+
+	/* Note: do not reorder, GCC is clever about common statements. */
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+			dev->name);
+		rx_mode =
+		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+		    AcceptAllPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else if ((dev->mc_count > multicast_filter_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else {
+		struct dev_mc_list *mclist;
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list;
+		     mclist && i < dev->mc_count;
+		     i++, mclist =
+		     mclist->next) set_bit (ether_crc (ETH_ALEN,
+						       mclist->
+						       dmi_addr) >> 26,
+					    mc_filter);
+	}
+	/* We can safely update without stopping the chip. */
+	RTL_W32 (RxConfig, tp->rx_config | rx_mode);
+	RTL_W32 (MAR0 + 0, mc_filter[0]);
+	RTL_W32 (MAR0 + 4, mc_filter[1]);
+
+	DPRINTK ("EXIT\n");
+}
+
+
+static void rtl8139_suspend (struct pci_dev *pdev)
+{
+	struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	void *ioaddr = tp->mmio_addr;
+
+	netif_stop_queue (dev);
+	
+	/* Disable interrupts, stop Tx and Rx. */
+	RTL_W16 (IntrMask, 0x0000);
+	RTL_W8 (ChipCmd, 0x00);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+	RTL_W32 (RxMissed, 0);
+}
+
+
+static void rtl8139_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
+
+	rtl8139_hw_start(dev);
+}
+
+
+static struct pci_driver rtl8139_pci_driver = {
+	name:		RTL8139_MODULE_NAME,
+	id_table:	rtl8139_pci_tbl,
+	probe:		rtl8139_init_one,
+	remove:		rtl8139_remove_one,
+	suspend:	rtl8139_suspend,
+	resume:		rtl8139_resume,
+};
+
+
+static int __init rtl8139_init_module (void)
+{
+	int rc;
+	
+	DPRINTK ("ENTER\n");
+
+	rc = pci_register_driver (&rtl8139_pci_driver);
+	
+	if (rc > 0) {
+		printk (KERN_INFO RTL8139_DRIVER_NAME
+			" loaded (%d device%s registered)\n",
+			rc, rc > 1 ? "s" : "");
+	}
+
+	DPRINTK ("EXIT\n");
+	return rc > 0 ? 0 : -ENODEV;
+}
+
+
+static void __exit rtl8139_cleanup_module (void)
+{
+	pci_unregister_driver (&rtl8139_pci_driver);
+}
+
+
+module_init(rtl8139_init_module);
+module_exit(rtl8139_cleanup_module);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.44/linux/drivers/net/Config.in	Thu Feb 10 17:11:09 2000
+++ linux/drivers/net/Config.in	Sun Feb 13 18:47:31 2000
@@ -73,7 +73,9 @@
       fi
       tristate '    SMC Ultra support' CONFIG_ULTRA
       tristate '    SMC Ultra32 EISA support' CONFIG_ULTRA32
-      tristate '    SMC 9194 support' CONFIG_SMC9194
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+         tristate '    SMC 9194 support' CONFIG_SMC9194
+      fi
   fi
   bool '  Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
   if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
@@ -83,10 +85,6 @@
     tristate '    NI5210 support' CONFIG_NI52
     tristate '    NI6510 support' CONFIG_NI65
   fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '  RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139
-      tristate '  DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
-   fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
    fi
@@ -94,18 +92,22 @@
    bool '  Other ISA cards' CONFIG_NET_ISA
    if [ "$CONFIG_NET_ISA" = "y" ]; then
       tristate '    Cabletron E21xx support' CONFIG_E2100
-      tristate '    EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+         tristate '    EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+      fi
       tristate '    EtherExpress 16 support' CONFIG_EEXPRESS
       tristate '    EtherExpressPro support' CONFIG_EEXPRESS_PRO
-      tristate '    FMV-181/182/183/184 support' CONFIG_FMV18X
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+         tristate '    FMV-181/182/183/184 support' CONFIG_FMV18X
+      fi
       tristate '    HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
       tristate '    HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
       tristate '    HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	 tristate '    ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+	 tristate '    ICL EtherTeam 16i/32 support' CONFIG_ETH16I
       fi
       tristate '    NE2000/NE1000 support' CONFIG_NE2000
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
 	 tristate '    SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
       fi
       bool '    SK_G16 support' CONFIG_SK_G16
@@ -114,8 +116,8 @@
       tristate '  SKnet MCA support' CONFIG_SKMC
       tristate '  NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
    fi
-   bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
-   if [ "$CONFIG_NET_EISA" = "y" ]; then
+   bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+   if [ "$CONFIG_NET_PCI" = "y" ]; then
       tristate '    AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 tristate '    Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
@@ -125,10 +127,15 @@
       fi
 
       tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
-      tristate '    CS89x0 support' CONFIG_CS89x0
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+         tristate '    CS89x0 support' CONFIG_CS89x0
+      fi
       tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
       tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
       tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+         tristate '    DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
+      fi
       tristate '    EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
@@ -136,18 +143,24 @@
       fi
       tristate '    PCI NE2000 support' CONFIG_NE2K_PCI
       # tristate '    Sundance Alta support' CONFIG_ALTA
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+         tristate '    RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129
+      fi
+      tristate '    RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO
       tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900
       tristate '    TI ThunderLAN support' CONFIG_TLAN
       tristate '    VIA Rhine support' CONFIG_VIA_RHINE
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 	 tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
 	 tristate '    SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
+      fi
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
 	 bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
       fi
    fi
    bool '  Pocket and portable adapters' CONFIG_NET_POCKET
    if [ "$CONFIG_NET_POCKET" = "y" ]; then
-      bool '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+      tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
       tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600
       tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620
    fi
@@ -234,7 +247,9 @@
 bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" = "y" ]; then
    dep_tristate '  STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
-   tristate '  AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+   if [ "$CONFIG_OBSOLETE" = "y" ]; then
+      tristate '  AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+   fi
    tristate '  Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
    tristate '  Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
    dep_tristate '   Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
diff -u --recursive --new-file v2.3.44/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.44/linux/drivers/net/Makefile	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/Makefile	Sun Feb 13 10:23:26 2000
@@ -228,7 +228,8 @@
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_EEXPRESS) += eexpress.o
 obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_RTL8139) += rtl8139.o
+obj-$(CONFIG_RTL8129) += rtl8129.o
+obj-$(CONFIG_8139TOO) += 8139too.o
 obj-$(CONFIG_WAVELAN) += wavelan.o
 obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
 obj-$(CONFIG_ZNET) += znet.o
diff -u --recursive --new-file v2.3.44/linux/drivers/net/a2065.c linux/drivers/net/a2065.c
--- v2.3.44/linux/drivers/net/a2065.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/a2065.c	Sun Feb 13 10:42:42 2000
@@ -164,7 +164,6 @@
 #define ZERO 0
 
 /* Setup the Lance Rx and Tx rings */
-/* Sets dev->tbusy */
 static void lance_init_ring (struct net_device *dev)
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
@@ -176,7 +175,7 @@
 	aib = lp->lance_init_block;
 
 	/* Lock out other processes while setting up hardware */
-	dev->tbusy = 1;
+	netif_stop_queue(dev);
 	lp->rx_new = lp->tx_new = 0;
 	lp->rx_old = lp->tx_old = 0;
 
@@ -442,11 +441,6 @@
 	if (!(csr0 & LE_C0_INTR))	/* Check if any interrupt has */
 		return;			/* been generated by the Lance. */
 
-	if (dev->interrupt)
-		printk ("%s: again", dev->name);
-
-	dev->interrupt = 1;
-
 	/* Acknowledge all the interrupt sources ASAP */
 	ll->rdp = csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|
 			   LE_C0_INIT);
@@ -473,15 +467,14 @@
 		ll->rdp = LE_C0_STRT;
 	}
 
-	if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
-		dev->tbusy = 0;
-		mark_bh (NET_BH);
-	}
+	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+	    TX_BUFFS_AVAIL > 0)
+		netif_wake_queue(dev);
+
 	ll->rap = LE_CSR0;
 	ll->rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|
 					LE_C0_IDON|LE_C0_INEA;
 
-	dev->interrupt = 0;
 }
 
 struct net_device *last_dev = 0;
@@ -506,9 +499,7 @@
 	load_csrs (lp);
 	lance_init_ring (dev);
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	netif_start_queue(dev);
 
 	status = init_restart_lance (lp);
 
@@ -522,9 +513,8 @@
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 	volatile struct lance_regs *ll = lp->ll;
 
-	dev->start = 0;
-	dev->tbusy = 1;
-	del_timer(&lp->multicast_timer);
+	netif_stop_queue(dev);
+	del_timer_sync(&lp->multicast_timer);
 
 	/* Stop the card */
 	ll->rap = LE_CSR0;
@@ -548,11 +538,11 @@
 	ll->rdp = LE_C0_STOP;
 
 	load_csrs (lp);
+
 	lance_init_ring (dev);
 	dev->trans_start = jiffies;
-	dev->interrupt = 0;
-	dev->start = 1;
-	dev->tbusy = 0;
+	netif_start_queue(dev);
+
 	status = init_restart_lance (lp);
 #ifdef DEBUG_DRIVER
 	printk ("Lance restart=%d\n", status);
@@ -560,6 +550,17 @@
 	return status;
 }
 
+static void lance_tx_timeout(struct net_device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
+
+	printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n",
+	       dev->name, ll->rdp);
+	lance_reset(dev);
+	netif_wake_queue(dev);
+}
+
 static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
 	struct lance_private *lp = (struct lance_private *)dev->priv;
@@ -570,26 +571,6 @@
 	static int outs;
 	unsigned long flags;
 
-	/* Transmitter timeout, serious problems */
-	if (dev->tbusy) {
-		int tickssofar = jiffies - dev->trans_start;
-	    
-		if (tickssofar < 100) {
-			status = -1;
-		} else {
-			printk ("%s: transmit timed out, status %04x, resetting\n",
-				dev->name, ll->rdp);
-			lance_reset (dev);
-		}
-		return status;
-	}
-
-	/* Block a timer-based transmit from overlapping. */
-	if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
-		printk ("Transmitter access conflict.\n");
-		return -1;
-	}
-
 	skblen = skb->len;
 
 	save_flags(flags);
@@ -628,13 +609,15 @@
 	lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
 
 	outs++;
+
+	if (TX_BUFFS_AVAIL <= 0)
+		netif_stop_queue(dev);
+
 	/* Kick the lance: transmit now */
 	ll->rdp = LE_C0_INEA | LE_C0_TDMD;
 	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
     
-	if (TX_BUFFS_AVAIL)
-		dev->tbusy = 0;
 	restore_flags(flags);
 
 	return status;
@@ -704,21 +687,17 @@
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_regs *ll = lp->ll;
 
-	if (!dev->start)
+	if (!test_bit(LINK_STATE_START, &dev->state))
 		return;
 
-	if (dev->tbusy) {
-		mod_timer(&lp->multicast_timer, jiffies + 2);
-		return;
-	}
-	set_bit (0, (void *) &dev->tbusy);
-
 	if (lp->tx_old != lp->tx_new) {
 		mod_timer(&lp->multicast_timer, jiffies + 4);
-		dev->tbusy = 0;
+		netif_wake_queue(dev);
 		return;
 	}
 
+	netif_stop_queue(dev);
+
 	ll->rap = LE_CSR0;
 	ll->rdp = LE_C0_STOP;
 	lance_init_ring (dev);
@@ -731,14 +710,19 @@
 	}
 	load_csrs (lp);
 	init_restart_lance (lp);
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
+	netif_wake_queue(dev);
 }
 
-int __init a2065_probe(struct net_device *dev)
+static int __init a2065_probe(void)
 {
+	struct net_device *dev = NULL;
+	static int called = 0;
 	struct zorro_dev *z = NULL;
 
+	if (called)
+		return -ENODEV;
+	called++;
+
 	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
 		unsigned long board, base_addr, ram_start;
 		int is_cbm;
@@ -765,6 +749,18 @@
 			continue;
 		}
 		strcpy(z->name, "A2065 Ethernet Card");
+
+		dev = init_etherdev(NULL, sizeof(struct lance_private));
+
+		if (dev == NULL) {
+			release_mem_region(base_addr,
+					   sizeof(struct lance_regs));
+			release_mem_region(ram_start, A2065_RAM_SIZE);
+			return -ENOMEM;
+		}
+		priv = (struct lance_private *)dev->priv;
+		memset(priv, 0, sizeof(struct lance_private));
+
 		if (is_cbm) {				/* Commodore */
 			dev->dev_addr[0] = 0x00;
 			dev->dev_addr[1] = 0x80;
@@ -782,18 +778,6 @@
 		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
-		init_etherdev(dev, 0);
-
-		dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL);
-		if (dev->priv == NULL) {
-			release_mem_region(base_addr,
-					   sizeof(struct lance_regs));
-			release_mem_region(ram_start, A2065_RAM_SIZE);
-			return -ENOMEM;
-		}
-		priv = (struct lance_private *)dev->priv;
-		memset(priv, 0, sizeof(struct lance_private));
-
 		dev->base_addr = ZTWO_VADDR(base_addr);
 		dev->mem_start = ZTWO_VADDR(ram_start);
 		dev->mem_end = dev->mem_start+A2065_RAM_SIZE;
@@ -812,6 +796,8 @@
 		dev->open = &lance_open;
 		dev->stop = &lance_close;
 		dev->hard_start_xmit = &lance_start_xmit;
+		dev->tx_timeout = &lance_tx_timeout;
+		dev->watchdog_timeo = 5*HZ;
 		dev->get_stats = &lance_get_stats;
 		dev->set_multicast_list = &lance_set_multicast;
 		dev->dma = 0;
@@ -828,31 +814,9 @@
 }
 
 
-#ifdef MODULE
-static char devicename[9] = { 0, };
-
-static struct net_device a2065_dev =
-{
-	devicename,			/* filled in by register_netdev() */
-	0, 0, 0, 0,			/* memory */
-	0, 0,				/* base, irq */
-	0, 0, 0, NULL, a2065_probe,
-};
-
-int init_module(void)
-{
-	int err;
-
-	if ((err = register_netdev(&a2065_dev))) {
-		if (err == -EIO)
-			printk("No A2065 board found. Module not loaded.\n");
-		return(err);
-	}
-	return(0);
-}
-
-void cleanup_module(void)
+static void __exit a2065_cleanup(void)
 {
+#ifdef MODULE
 	struct lance_private *priv = (struct lance_private *)a2065_dev.priv;
 
 	unregister_netdev(&a2065_dev);
@@ -860,6 +824,8 @@
 			   sizeof(struct lance_regs));
 	release_mem_region(ZTWO_PADDR(a2065_dev.mem_start), A2065_RAM_SIZE);
 	kfree(priv);
+#endif
 }
 
-#endif /* MODULE */
+module_init(a2065_probe);
+module_exit(a2065_cleanup);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/arc-rimi.c linux/drivers/net/arcnet/arc-rimi.c
--- v2.3.44/linux/drivers/net/arcnet/arc-rimi.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/arc-rimi.c	Sun Feb 13 10:38:11 2000
@@ -2,7 +2,7 @@
  * Linux ARCnet driver - "RIM I" (entirely mem-mapped) cards
  * 
  * Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
  * Derived from skeleton.c by Donald Becker.
  *
  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -325,20 +325,11 @@
 {
 	struct net_device *dev = my_dev;
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
-	void *ioaddr = lp->mem_start + 0x800;
-
-	if (dev->start)
-		dev->stop(dev);
-
-	/* Flush TX and disable RX */
-	AINTMASK(0);		/* disable IRQ's */
-	ACOMMAND(NOTXcmd);	/* stop transmit */
-	ACOMMAND(NORXcmd);	/* disable receive */
 
+	unregister_netdev(dev);
 	free_irq(dev->irq, dev);
 	iounmap(lp->mem_start);
 	release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
-	unregister_netdev(dev);
 	kfree(dev->priv);
 	kfree(dev);
 }
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c
--- v2.3.44/linux/drivers/net/arcnet/arcnet.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/arcnet.c	Sun Feb 13 10:38:11 2000
@@ -3,7 +3,7 @@
  * 
  * Written 1997 by David Woodhouse.
  * Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
  * Derived from skeleton.c by Donald Becker.
  *
  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -41,7 +41,7 @@
  *     <jojo@repas.de>
  */
 
-#define VERSION "arcnet: v3.91 BETA 99/12/18 - by Avery Pennarun et al.\n"
+#define VERSION "arcnet: v3.92 BETA 2000/02/13 - by Avery Pennarun et al.\n"
 
 #include <linux/module.h>
 #include <linux/config.h>
@@ -97,6 +97,7 @@
 static int arcnet_open(struct net_device *dev);
 static int arcnet_close(struct net_device *dev);
 static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void arcnet_timeout(struct net_device *dev);
 static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
 			 unsigned short type, void *daddr, void *saddr,
 			 unsigned len);
@@ -347,6 +348,7 @@
 	dev->addr_len = 1;
 	dev->tx_queue_len = 30;
 	dev->broadcast[0] = 0x00;	/* for us, broadcasts are address 0 */
+	dev->watchdog_timeo = TX_TIMEOUT;
 
 	/* New-style flags. */
 	dev->flags = IFF_BROADCAST;
@@ -358,6 +360,7 @@
 	dev->open = arcnet_open;
 	dev->stop = arcnet_close;
 	dev->hard_start_xmit = arcnet_send_packet;
+	dev->tx_timeout = arcnet_timeout;
 	dev->get_stats = arcnet_get_stats;
 	dev->hard_header = arcnet_header;
 	dev->rebuild_header = arcnet_rebuild_header;
@@ -397,10 +400,6 @@
 	if (ARCRESET(0) && ARCRESET(1))
 		return -ENODEV;
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 0;
-
 	newmtu = choose_mtu();
 	if (newmtu < dev->mtu)
 		dev->mtu = newmtu;
@@ -441,9 +440,6 @@
 	if (ASTATUS() & RESETflag)
 		ACOMMAND(CFLAGScmd | RESETclear);
 
-	/* we're started */
-	dev->start = 1;
-
 	/* make sure we're ready to receive IRQ's. */
 	AINTMASK(0);
 	udelay(1);		/* give it time to set the mask before
@@ -453,6 +449,8 @@
 	lp->intmask = NORXflag | RECONflag;
 	AINTMASK(lp->intmask);
 
+	netif_start_queue(dev);
+
 	return 0;
 }
 
@@ -462,16 +460,14 @@
 {
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 
+	netif_stop_queue(dev);
+
 	/* flush TX and disable RX */
 	AINTMASK(0);
 	ACOMMAND(NOTXcmd);	/* stop transmit */
 	ACOMMAND(NORXcmd);	/* disable receive */
 	mdelay(1);
 
-	dev->tbusy = 1;
-	dev->start = 0;
-	dev->interrupt = 0;
-
 	/* shut down the card */
 	ARCOPEN(0);
 
@@ -584,48 +580,6 @@
 	       "transmit requested (status=%Xh, txbufs=%d/%d, len=%d)\n",
 	       ASTATUS(), lp->cur_tx, lp->next_tx, skb->len);
 
-	if (dev->tbusy) {
-		/*
-		 * If we get here, some higher level has decided we are broken.
-		 * There should really be a "kick me" function call instead. 
-		 */
-		unsigned long flags;
-		int tickssofar = jiffies - dev->trans_start, status = ASTATUS();
-
-		if (tickssofar < TX_TIMEOUT) {
-			BUGMSG(D_DURING, "premature kickme! (status=%Xh ticks=%d)\n",
-			       status, tickssofar);
-			return 1;	/* means "try again" */
-		}
-		save_flags(flags);
-		cli();
-
-		if (status & TXFREEflag) {	/* transmit _DID_ finish */
-			BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
-			       status, tickssofar, lp->intmask, lp->lasttrans_dest);
-			lp->stats.tx_errors++;
-		} else {
-			BUGMSG(D_EXTRA, "tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n",
-			       status, tickssofar, lp->intmask, lp->lasttrans_dest);
-			lp->stats.tx_errors++;
-			lp->stats.tx_aborted_errors++;
-
-			ACOMMAND(NOTXcmd | (lp->cur_tx << 3));
-		}
-
-		/*
-		 * interrupt handler will set dev->tbusy = 0 when it notices the
-		 * transmit has been canceled.
-		 */
-
-		/* make sure we didn't miss a TX IRQ */
-		AINTMASK(0);
-		lp->intmask |= TXFREEflag;
-		AINTMASK(lp->intmask);
-
-		restore_flags(flags);
-		return 1;
-	}
 	pkt = (struct archdr *) skb->data;
 	soft = &pkt->soft.rfc1201;
 	proto = arc_proto_map[soft->proto];
@@ -638,18 +592,10 @@
 		dev_kfree_skb(skb);
 		return 0;	/* don't try again */
 	}
-	/*
-	 * Block a timer-based transmit from overlapping.  This could better be
-	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. 
-	 */
-	if (test_and_set_bit(0, (int *) &dev->tbusy)) {
-		BUGMSG(D_NORMAL, "transmitter called with busy bit set! "
-		       "(status=%Xh, tickssofar=%ld)\n",
-		       ASTATUS(), jiffies - dev->trans_start);
-		lp->stats.tx_errors++;
-		lp->stats.tx_fifo_errors++;
-		return 0;	/* don't try again */
-	}
+
+	/* We're busy transmitting a packet... */
+	netif_stop_queue(dev);
+
 	AINTMASK(0);
 
 	txbuf = get_arcbuf(dev);
@@ -718,6 +664,37 @@
 }
 
 
+/* Called by the kernel when transmit times out */
+static void arcnet_timeout(struct net_device *dev)
+{
+	unsigned long flags;
+	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
+	int status = ASTATUS();
+
+	save_flags(flags);
+	cli();
+
+	if (status & TXFREEflag) {	/* transmit _DID_ finish */
+		BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, mask=%Xh, dest=%02Xh)\n",
+		       status, lp->intmask, lp->lasttrans_dest);
+		lp->stats.tx_errors++;
+	} else {
+		BUGMSG(D_EXTRA, "tx timed out (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
+		       status, lp->intmask, lp->lasttrans_dest);
+		lp->stats.tx_errors++;
+		lp->stats.tx_aborted_errors++;
+		ACOMMAND(NOTXcmd | (lp->cur_tx << 3));
+	}
+
+	/* make sure we didn't miss a TX IRQ */
+	AINTMASK(0);
+	lp->intmask |= TXFREEflag;
+	AINTMASK(lp->intmask);
+
+	restore_flags(flags);
+}
+
+
 /*
  * The typical workload of the driver: Handle the network interface
  * interrupts. Establish which device needs attention, and call the correct
@@ -743,25 +720,20 @@
 		return;
 	}
 	/*
-	 * RESET flag was enabled - if !dev->start, we must clear it right
+	 * RESET flag was enabled - if device is not running, we must clear it right
 	 * away (but nothing else).
 	 */
-	if (!dev->start) {
+	if (!test_bit(LINK_STATE_START, &dev->state)) {
 		if (ASTATUS() & RESETflag)
 			ACOMMAND(CFLAGScmd | RESETclear);
 		AINTMASK(0);
 		return;
 	}
-	if (dev->interrupt) {
-		BUGMSG(D_NORMAL, "DRIVER PROBLEM!  Nested arcnet interrupts!\n");
-		return;		/* don't even try. */
-	}
-	dev->interrupt = 1;
 
 	BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
 	       ASTATUS(), lp->intmask);
 
-	boguscount = 3;
+	boguscount = 5;
 	do {
 		status = ASTATUS();
 		didsomething = 0;
@@ -839,17 +811,15 @@
 					if (lp->outgoing.proto->continue_tx(dev, txbuf)) {
 						/* that was the last segment */
 						lp->stats.tx_bytes += lp->outgoing.skb->len;
-						dev_kfree_skb(lp->outgoing.skb);
+						dev_kfree_skb_irq(lp->outgoing.skb);
 						lp->outgoing.proto = NULL;
 					}
 					lp->next_tx = txbuf;
 				}
 			}
 			/* inform upper layers of idleness, if necessary */
-			if (lp->cur_tx == -1) {
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
+			if (lp->cur_tx == -1)
+				netif_wake_queue(dev);
 		}
 		/* now process the received packet, if any */
 		if (recbuf != -1) {
@@ -922,8 +892,6 @@
 	AINTMASK(0);
 	udelay(1);
 	AINTMASK(lp->intmask);
-
-	dev->interrupt = 0;
 }
 
 
@@ -987,11 +955,6 @@
 	}
 	/* call the protocol-specific receiver. */
 	arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
-
-	/*
-	 * If any worthwhile packets have been received, a mark_bh(NET_BH) has
-	 * been done by netif_rx and Linux will handle them after we return.
-	 */
 }
 
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com20020-isa.c linux/drivers/net/arcnet/com20020-isa.c
--- v2.3.44/linux/drivers/net/arcnet/com20020-isa.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/com20020-isa.c	Sun Feb 13 10:38:11 2000
@@ -3,7 +3,7 @@
  * 
  * Written 1997 by David Woodhouse.
  * Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
  * Derived from skeleton.c by Donald Becker.
  *
  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -176,12 +176,9 @@
 {
 	struct net_device *dev = my_dev;
 
-	if (dev->start)
-		dev->stop(dev);
-
+	unregister_netdev(dev);
 	free_irq(dev->irq, dev);
 	release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-	unregister_netdev(dev);
 	kfree(dev->priv);
 	kfree(dev);
 }
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c
--- v2.3.44/linux/drivers/net/arcnet/com20020-pci.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/com20020-pci.c	Sun Feb 13 10:38:11 2000
@@ -3,7 +3,7 @@
  * 
  * Written 1994-1999 by Avery Pennarun,
  *    based on an ISA version by David Woodhouse.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
  * Derived from skeleton.c by Donald Becker.
  *
  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -148,13 +148,9 @@
 
 	for (count = 0; count < numcards; count++) {
 		dev = cards[count];
-
-		if (dev->start)
-			dev->stop(dev);
-
+		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
 		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-		unregister_netdev(dev);
 		kfree(dev->priv);
 		kfree(dev);
 	}
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com90io.c linux/drivers/net/arcnet/com90io.c
--- v2.3.44/linux/drivers/net/arcnet/com90io.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/com90io.c	Sun Feb 13 10:38:11 2000
@@ -3,7 +3,7 @@
  * 
  * Written 1997 by David Woodhouse.
  * Written 1994-1999 by Avery Pennarun.
- * Written 1999 by Martin Mares <mj@suse.cz>.
+ * Written 1999-2000 by Martin Mares <mj@suse.cz>.
  * Derived from skeleton.c by Donald Becker.
  *
  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
@@ -406,20 +406,13 @@
 	struct net_device *dev = my_dev;
 	int ioaddr = dev->base_addr;
 
-	if (dev->start)
-		dev->stop(dev);
-
-	/* Flush TX and disable RX */
-	AINTMASK(0);		/* disable IRQ's */
-	ACOMMAND(NOTXcmd);	/* stop transmit */
-	ACOMMAND(NORXcmd);	/* disable receive */
+	unregister_netdev(dev);
 
 	/* Set the thing back to MMAP mode, in case the old driver is loaded later */
 	outb((inb(_CONFIG) & ~IOMAPflag), _CONFIG);
 
 	free_irq(dev->irq, dev);
 	release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
-	unregister_netdev(dev);
 	kfree(dev->priv);
 	kfree(dev);
 }
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/com90xx.c linux/drivers/net/arcnet/com90xx.c
--- v2.3.44/linux/drivers/net/arcnet/com90xx.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/com90xx.c	Sun Feb 13 10:38:11 2000
@@ -143,7 +143,7 @@
 		numprint %= 8;
 		if (!numprint) {
 			BUGMSG2(D_INIT, "\n");
-			BUGMSG(D_INIT, "S1: ");
+			BUGMSG2(D_INIT, "S1: ");
 		}
 		BUGMSG2(D_INIT, "%Xh ", *port);
 
@@ -151,7 +151,7 @@
 
 		if (check_region(*port, ARCNET_TOTAL_SIZE)) {
 			BUGMSG2(D_INIT_REASONS, "(check_region)\n");
-			BUGMSG(D_INIT_REASONS, "S1: ");
+			BUGMSG2(D_INIT_REASONS, "S1: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
 			*port = ports[numports - 1];
 			numports--;
@@ -160,7 +160,7 @@
 		}
 		if (ASTATUS() == 0xFF) {
 			BUGMSG2(D_INIT_REASONS, "(empty)\n");
-			BUGMSG(D_INIT_REASONS, "S1: ");
+			BUGMSG2(D_INIT_REASONS, "S1: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
 			*port = ports[numports - 1];
 			numports--;
@@ -170,13 +170,13 @@
 		inb(_RESET);	/* begin resetting card */
 
 		BUGMSG2(D_INIT_REASONS, "\n");
-		BUGMSG(D_INIT_REASONS, "S1: ");
+		BUGMSG2(D_INIT_REASONS, "S1: ");
 		BUGLVL(D_INIT_REASONS) numprint = 0;
 	}
 	BUGMSG2(D_INIT, "\n");
 
 	if (!numports) {
-		BUGMSG(D_NORMAL, "S1: No ARCnet cards found.\n");
+		BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n");
 		return -ENODEV;
 	}
 	/* Stage 2: we have now reset any possible ARCnet cards, so we can't
@@ -189,7 +189,7 @@
 		numprint %= 8;
 		if (!numprint) {
 			BUGMSG2(D_INIT, "\n");
-			BUGMSG(D_INIT, "S2: ");
+			BUGMSG2(D_INIT, "S2: ");
 		}
 		BUGMSG2(D_INIT, "%Xh ", *port);
 	}
@@ -207,13 +207,13 @@
 		numprint %= 8;
 		if (!numprint) {
 			BUGMSG2(D_INIT, "\n");
-			BUGMSG(D_INIT, "S3: ");
+			BUGMSG2(D_INIT, "S3: ");
 		}
 		BUGMSG2(D_INIT, "%lXh ", *shmem);
 
 		if (check_mem_region(*shmem, BUFFER_SIZE)) {
 			BUGMSG2(D_INIT_REASONS, "(check_mem_region)\n");
-			BUGMSG(D_INIT_REASONS, "Stage 3: ");
+			BUGMSG2(D_INIT_REASONS, "Stage 3: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
 			*shmem = shmems[numshmems - 1];
 			numshmems--;
@@ -223,7 +223,7 @@
 		if (isa_readb(ptr) != TESTvalue) {
 			BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n",
 				isa_readb(ptr), TESTvalue);
-			BUGMSG(D_INIT_REASONS, "S3: ");
+			BUGMSG2(D_INIT_REASONS, "S3: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
 			*shmem = shmems[numshmems - 1];
 			numshmems--;
@@ -238,20 +238,20 @@
 		isa_writeb(0x42, ptr);
 		if (isa_readb(ptr) != 0x42) {
 			BUGMSG2(D_INIT_REASONS, "(read only)\n");
-			BUGMSG(D_INIT_REASONS, "S3: ");
+			BUGMSG2(D_INIT_REASONS, "S3: ");
 			*shmem = shmems[numshmems - 1];
 			numshmems--;
 			shmem--;
 			continue;
 		}
 		BUGMSG2(D_INIT_REASONS, "\n");
-		BUGMSG(D_INIT_REASONS, "S3: ");
+		BUGMSG2(D_INIT_REASONS, "S3: ");
 		BUGLVL(D_INIT_REASONS) numprint = 0;
 	}
 	BUGMSG2(D_INIT, "\n");
 
 	if (!numshmems) {
-		BUGMSG(D_NORMAL, "S3: No ARCnet cards found.\n");
+		BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n");
 		return -ENODEV;
 	}
 	/* Stage 4: something of a dummy, to report the shmems that are
@@ -263,7 +263,7 @@
 		numprint %= 8;
 		if (!numprint) {
 			BUGMSG2(D_INIT, "\n");
-			BUGMSG(D_INIT, "S4: ");
+			BUGMSG2(D_INIT, "S4: ");
 		}
 		BUGMSG2(D_INIT, "%lXh ", *shmem);
 	}
@@ -282,7 +282,7 @@
 		numprint %= 8;
 		if (!numprint) {
 			BUGMSG2(D_INIT, "\n");
-			BUGMSG(D_INIT, "S5: ");
+			BUGMSG2(D_INIT, "S5: ");
 		}
 		BUGMSG2(D_INIT, "%Xh ", *port);
 
@@ -292,7 +292,7 @@
 		if ((status & 0x9D)
 		    != (NORXflag | RECONflag | TXFREEflag | RESETflag)) {
 			BUGMSG2(D_INIT_REASONS, "(status=%Xh)\n", status);
-			BUGMSG(D_INIT_REASONS, "S5: ");
+			BUGMSG2(D_INIT_REASONS, "S5: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
 			*port = ports[numports - 1];
 			numports--;
@@ -304,7 +304,7 @@
 		if (status & RESETflag) {
 			BUGMSG2(D_INIT_REASONS, " (eternal reset, status=%Xh)\n",
 				status);
-			BUGMSG(D_INIT_REASONS, "S5: ");
+			BUGMSG2(D_INIT_REASONS, "S5: ");
 			BUGLVL(D_INIT_REASONS) numprint = 0;
 			*port = ports[numports - 1];
 			numports--;
@@ -327,7 +327,7 @@
 
 			if (airq <= 0) {
 				BUGMSG2(D_INIT_REASONS, "(airq=%d)\n", airq);
-				BUGMSG(D_INIT_REASONS, "S5: ");
+				BUGMSG2(D_INIT_REASONS, "S5: ");
 				BUGLVL(D_INIT_REASONS) numprint = 0;
 				*port = ports[numports - 1];
 				numports--;
@@ -398,7 +398,7 @@
 		isa_writeb(TESTvalue, *shmem);
 
 	if (retval && dev && !numcards)
-		BUGMSG(D_NORMAL, "S5: No ARCnet cards found.\n");
+		BUGMSG2(D_NORMAL, "S5: No ARCnet cards found.\n");
 	return retval;
 }
 
@@ -416,7 +416,7 @@
 
 	/* allocate struct net_device if we don't have one yet */
 	if (!dev && !(dev = dev_alloc("arc%d", &err))) {
-		BUGMSG(D_NORMAL, "Can't allocate device!\n");
+		BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n");
 		return err;
 	}
 	lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
@@ -546,8 +546,7 @@
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 	short ioaddr = dev->base_addr;
 
-	BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
-	       dev->name, ASTATUS());
+	BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS());
 
 	if (really_reset) {
 		/* reset the card */
@@ -653,13 +652,11 @@
 		dev = cards[count];
 		lp = (struct arcnet_local *) dev->priv;
 
-		if (dev->start)
-			dev->stop(dev);
+		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
 		iounmap(lp->mem_start);
 		release_region(dev->base_addr, ARCNET_TOTAL_SIZE);
 		release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1);
-		unregister_netdev(dev);
 		kfree(dev->priv);
 		kfree(dev);
 	}
diff -u --recursive --new-file v2.3.44/linux/drivers/net/arcnet/rfc1201.c linux/drivers/net/arcnet/rfc1201.c
--- v2.3.44/linux/drivers/net/arcnet/rfc1201.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/arcnet/rfc1201.c	Sun Feb 13 10:38:11 2000
@@ -171,7 +171,7 @@
 			BUGMSG(D_EXTRA, "aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
 			 in->sequence, soft->split_flag, soft->sequence);
 			lp->rfc1201.aborted_seq = soft->sequence;
-			kfree_skb(in->skb);
+			dev_kfree_skb_irq(in->skb);
 			lp->stats.rx_errors++;
 			lp->stats.rx_missed_errors++;
 			in->skb = NULL;
@@ -255,7 +255,7 @@
 			BUGMSG(D_EXTRA, "wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
 			       saddr, in->sequence, soft->sequence,
 			       soft->split_flag);
-			kfree_skb(in->skb);
+			dev_kfree_skb_irq(in->skb);
 			in->skb = NULL;
 			lp->stats.rx_errors++;
 			lp->stats.rx_missed_errors++;
@@ -271,7 +271,7 @@
 				       soft->sequence);
 				lp->stats.rx_errors++;
 				lp->stats.rx_missed_errors++;
-				kfree_skb(in->skb);
+				dev_kfree_skb_irq(in->skb);
 			}
 			in->sequence = soft->sequence;
 			in->numpackets = ((unsigned) soft->split_flag >> 1) + 2;
@@ -332,7 +332,7 @@
 				       "(seq=%d) aborted (splitflag=%d, seq=%d)\n",
 				       in->sequence, soft->split_flag, soft->sequence);
 				lp->rfc1201.aborted_seq = soft->sequence;
-				kfree_skb(in->skb);
+				dev_kfree_skb_irq(in->skb);
 				in->skb = NULL;
 				lp->stats.rx_errors++;
 				lp->stats.rx_missed_errors++;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v2.3.44/linux/drivers/net/ariadne.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/ariadne.c	Sun Feb 13 11:21:42 2000
@@ -160,6 +160,16 @@
 	    continue;
 	}
 	strcpy(z->name, "Ariadne Ethernet Card and Parallel Ports");
+
+	dev = init_etherdev(NULL, sizeof(struct ariadne_private));
+
+	if (dev == NULL) {
+	    release_mem_region(base_addr, sizeof(struct Am79C960));
+	    release_mem_region(ram_start, ARIADNE_RAM_SIZE);
+	    return -ENOMEM;
+	}
+	memset(dev->priv, 0, sizeof(struct ariadne_private));
+
 	dev->dev_addr[0] = 0x00;
 	dev->dev_addr[1] = 0x60;
 	dev->dev_addr[2] = 0x30;
@@ -170,16 +180,6 @@
 	       "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
 	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-
-	init_etherdev(dev, 0);
-
-	dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL);
-	if (dev->priv == NULL) {
-	    release_mem_region(base_addr, sizeof(struct Am79C960));
-	    release_mem_region(ram_start, ARIADNE_RAM_SIZE);
-	    return -ENOMEM;
-	}
-	memset(dev->priv, 0, sizeof(struct ariadne_private));
 
 	dev->base_addr = ZTWO_VADDR(base_addr);
 	dev->mem_start = ZTWO_VADDR(ram_start);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.3.44/linux/drivers/net/atp.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/atp.c	Sun Feb 13 18:20:21 2000
@@ -16,6 +16,8 @@
 		Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
 	The timer-based reset code was written by Bill Carlson, wwc@super.org.
+	
+	Modular support/softnet added by Alan Cox.
 */
 
 static const char *version =
@@ -82,6 +84,7 @@
 */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -101,6 +104,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 
 #include "atp.h"
 
@@ -133,9 +137,10 @@
 static unsigned short eeprom_op(short ioaddr, unsigned int cmd);
 static int net_open(struct net_device *dev);
 static void hardware_init(struct net_device *dev);
+static void tx_timeout(struct net_device *dev);
 static void write_packet(short ioaddr, int length, unsigned char *packet, int mode);
 static void trigger_send(short ioaddr, int length);
-static int	net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void net_rx(struct net_device *dev);
 static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
@@ -150,8 +155,8 @@
    If dev->base_addr == 2, allocate space for the device and return success
    (detachable devices only).
    */
-int __init 
-atp_init(struct net_device *dev)
+
+int __init atp_init(struct net_device *dev)
 {
 	int *port, ports[] = {0x378, 0x278, 0x3bc, 0};
 	int base_addr = dev->base_addr;
@@ -220,7 +225,7 @@
 		   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
 
 	/* Leave the hardware in a reset state. */
-    write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+	write_reg_high(ioaddr, CMR1, CMR1h_RESET);
 
 	if (net_debug)
 		printk(version);
@@ -231,11 +236,10 @@
 	if (dev->priv == NULL)
 		return -ENOMEM;
 	memset(dev->priv, 0, sizeof(struct net_local));
-
-
 	{
 		struct net_local *lp = (struct net_local *)dev->priv;
 		lp->addr_mode = CMR2h_Normal;
+		spin_lock_init(&lp->lock);
 	}
 
 	/* For the ATP adapter the "if_port" is really the data transfer mode. */
@@ -245,9 +249,11 @@
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
-	dev->hard_start_xmit = net_send_packet;
-	dev->get_stats	= net_get_stats;
-	dev->set_multicast_list = &set_multicast_list;
+	dev->hard_start_xmit 	= net_send_packet;
+	dev->get_stats		= net_get_stats;
+	dev->set_multicast_list = set_multicast_list;
+	dev->tx_timeout		= tx_timeout;
+	dev->watchdog_timeo	= HZ/20;
 
 #ifdef TIMED_CHECKER
 	del_timer(&atp_timer);
@@ -327,12 +333,12 @@
 	/* The interrupt line is turned off (tri-stated) when the device isn't in
 	   use.  That's especially important for "attached" interfaces where the
 	   port or interrupt may be shared. */
+	   
 	if (request_irq(dev->irq, &net_interrupt, 0, "ATP", dev)) {
 		return -EAGAIN;
 	}
-
 	hardware_init(dev);
-	dev->start = 1;
+	netif_start_queue(dev);
 	return 0;
 }
 
@@ -342,11 +348,11 @@
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-    int i;
+	int i;
 
 	write_reg_high(ioaddr, CMR1, CMR1h_RESET);
 	
-    for (i = 0; i < 6; i++)
+	for (i = 0; i < 6; i++)
 		write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
 
 	write_reg_high(ioaddr, CMR2, lp->addr_mode);
@@ -356,22 +362,19 @@
 			   (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f);
 	}
 
-    write_reg(ioaddr, CMR2, CMR2_IRQOUT);
-    write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
+	write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+	write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
 
 	/* Enable the interrupt line from the serial port. */
 	outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
 
 	/* Unmask the interesting interrupts. */
-    write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
-    write_reg_high(ioaddr, IMR, ISRh_RxErr);
+	write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+	write_reg_high(ioaddr, IMR, ISRh_RxErr);
 
 	lp->tx_unit_busy = 0;
-    lp->pac_cnt_in_tx_buf = 0;
+	lp->pac_cnt_in_tx_buf = 0;
 	lp->saved_tx_size = 0;
-
-	dev->tbusy = 0;
-	dev->interrupt = 0;
 }
 
 static void trigger_send(short ioaddr, int length)
@@ -383,15 +386,15 @@
 
 static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode)
 {
-    length = (length + 1) & ~1;		/* Round up to word length. */
-    outb(EOC+MAR, ioaddr + PAR_DATA);
-    if ((data_mode & 1) == 0) {
+	length = (length + 1) & ~1;		/* Round up to word length. */
+	outb(EOC+MAR, ioaddr + PAR_DATA);
+	if ((data_mode & 1) == 0) {
 		/* Write the packet out, starting with the write addr. */
 		outb(WrAddr+MAR, ioaddr + PAR_DATA);
 		do {
 			write_byte_mode0(ioaddr, *packet++);
 		} while (--length > 0) ;
-    } else {
+	} else {
 		/* Write the packet out in slow mode. */
 		unsigned char outbyte = *packet++;
 
@@ -405,70 +408,61 @@
 		outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
 		while (--length > 0)
 			write_byte_mode1(ioaddr, *packet++);
-    }
-    /* Terminate the Tx frame.  End of write: ECB. */
-    outb(0xff, ioaddr + PAR_DATA);
-    outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+	}
+	/* Terminate the Tx frame.  End of write: ECB. */
+	outb(0xff, ioaddr + PAR_DATA);
+	outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
 }
 
-static int
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void tx_timeout(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
+	/* If we get here, some higher level has decided we are broken. */
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+		   inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
+		   :  "IRQ conflict");
+	lp->stats.tx_errors++;
+	/* Try to restart the adapter. */
+	hardware_init(dev);
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
 
-	if (dev->tbusy) {
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		printk("%s: transmit timed out, %s?\n", dev->name,
-			   inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
-			   :  "IRQ conflict");
-		lp->stats.tx_errors++;
-		/* Try to restart the adapter. */
-		hardware_init(dev);
-		dev->tbusy=0;
-		dev->trans_start = jiffies;
-	}
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char *buf = skb->data;
+	unsigned long flags;
+	
+	netif_stop_queue(dev);
+	
+	/* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
+	   This sequence must not be interrupted by an incoming packet. */
+	   
+	spin_lock_irqsave(&lp->lock, flags);
+	write_reg(ioaddr, IMR, 0);
+	write_reg_high(ioaddr, IMR, 0);
+	spin_unlock_irqrestore(&lp->lock, flags);
+	
+	write_packet(ioaddr, length, buf, dev->if_port);
 
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-		printk("%s: Transmitter access conflict.\n", dev->name);
-	else {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
-		int flags;
-
-		/* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
-		   This sequence must not be interrupted by an incoming packet. */
-		save_flags(flags);
-		cli();
-		write_reg(ioaddr, IMR, 0);
-		write_reg_high(ioaddr, IMR, 0);
-		restore_flags(flags);
-
-		write_packet(ioaddr, length, buf, dev->if_port);
-
-		lp->pac_cnt_in_tx_buf++;
-		if (lp->tx_unit_busy == 0) {
-			trigger_send(ioaddr, length);
-			lp->saved_tx_size = 0; 				/* Redundant */
-			lp->re_tx = 0;
+	lp->pac_cnt_in_tx_buf++;
+	if (lp->tx_unit_busy == 0) {
+		trigger_send(ioaddr, length);
+		lp->saved_tx_size = 0; 				/* Redundant */
+		lp->re_tx = 0;
 			lp->tx_unit_busy = 1;
-		} else
-			lp->saved_tx_size = length;
-
-		dev->trans_start = jiffies;
-		/* Re-enable the LPT interrupts. */
-		write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
-		write_reg_high(ioaddr, IMR, ISRh_RxErr);
-	}
+	} else
+		lp->saved_tx_size = length;
 
+	dev->trans_start = jiffies;
+	/* Re-enable the LPT interrupts. */
+	write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+	write_reg_high(ioaddr, IMR, ISRh_RxErr);
 	dev_kfree_skb (skb);
-
 	return 0;
 }
 
@@ -482,14 +476,10 @@
 	int ioaddr, status, boguscount = 20;
 	static int num_tx_since_rx = 0;
 
-	if (dev == NULL) {
-		printk ("ATP_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
-	dev->interrupt = 1;
-
 	ioaddr = dev->base_addr;
 	lp = (struct net_local *)dev->priv;
+	
+	spin_lock(&lp->lock);
 
 	/* Disable additional spurious interrupts. */
 	outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
@@ -498,10 +488,14 @@
 	write_reg(ioaddr, CMR2, CMR2_NULL);
 	write_reg(ioaddr, IMR, 0);
 
-	if (net_debug > 5) printk("%s: In interrupt ", dev->name);
-    while (--boguscount > 0) {
+	if (net_debug > 5)
+		printk("%s: In interrupt ", dev->name);
+
+	while (--boguscount > 0) 
+	{
 		status = read_nibble(ioaddr, ISR);
-		if (net_debug > 5) printk("loop status %02x..", status);
+		if (net_debug > 5)
+			printk("loop status %02x..", status);
 
 		if (status & (ISR_RxOK<<3)) {
 			write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */
@@ -539,7 +533,8 @@
 					break;
 				}
 				/* Attempt to retransmit. */
-				if (net_debug > 6)  printk("attempting to ReTx");
+				if (net_debug > 6)
+					printk("attempting to ReTx");
 				write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
 			} else {
 				/* Finish up the transmit. */
@@ -551,8 +546,7 @@
 					lp->re_tx = 0;
 				} else
 					lp->tx_unit_busy = 0;
-				dev->tbusy = 0;
-				mark_bh(NET_BH);	/* Inform upper layers. */
+				netif_wake_queue(dev);	/* Inform upper layers. */
 			}
 			num_tx_since_rx++;
 		} else if (num_tx_since_rx > 8
@@ -568,7 +562,7 @@
 			break;
 		} else
 			break;
-    }
+	}
 
 	/* This following code fixes a rare (and very difficult to track down)
 	   problem where the adapter forgets its ethernet address. */
@@ -584,17 +578,17 @@
 	}
 
 	/* Tell the adapter that it can go back to using the output line as IRQ. */
-    write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+	write_reg(ioaddr, CMR2, CMR2_IRQOUT);
 	/* Enable the physical interrupt line, which is sure to be low until.. */
 	outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
 	/* .. we enable the interrupt sources. */
 	write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
 	write_reg_high(ioaddr, IMR, ISRh_RxErr); 			/* Hmmm, really needed? */
 
-	if (net_debug > 5) printk("exiting interrupt.\n");
-
-	dev->interrupt = 0;
-
+	if (net_debug > 5)
+		printk("exiting interrupt.\n");
+		
+	spin_unlock(&lp->lock);
 	return;
 }
 
@@ -603,33 +597,17 @@
    problem where the adapter forgets its ethernet address. */
 static void atp_timed_checker(unsigned long ignored)
 {
-  int i;
-  int ioaddr = atp_timed_dev->base_addr;
+	int i;
+	struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
+	int ioaddr = atp_timed_dev->base_addr;
 
-  if (!atp_timed_dev->interrupt)
-	{
-	  for (i = 0; i < 6; i++)
-#if 0
-		if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i])
-		  {
-			struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
-			write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
-			if (i == 2)
-			  lp->stats.tx_errors++;
-			else if (i == 3)
-			  lp->stats.tx_dropped++;
-			else if (i == 4)
-			  lp->stats.collisions++;
-			else
-			  lp->stats.rx_errors++;
-		  }
-#else
-	  write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
-#endif
-	}
-  del_timer(&atp_timer);
-  atp_timer.expires = jiffies + TIMED_CHECKER;
-  add_timer(&atp_timer);
+	spin_lock(&lp->lock);
+	for (i = 0; i < 6; i++)
+		write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
+	spin_unlock(&lp->lock);
+	del_timer(&atp_timer);
+	atp_timer.expires = jiffies + TIMED_CHECKER;
+	add_timer(&atp_timer);
 }
 #endif
 
@@ -707,19 +685,17 @@
 	else
 		do      *p++ = read_byte_mode6(ioaddr);  while (--length > 0);
 
-    outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
+	outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
 	outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
 }
 
 /* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
+static int net_close(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 
-	dev->tbusy = 1;
-	dev->start = 0;
+	netif_stop_queue(dev);
 
 	/* Flush the Tx and disable Rx here. */
 	lp->addr_mode = CMR2h_OFF;
@@ -730,7 +706,7 @@
 	free_irq(dev->irq, dev);
 
 	/* Leave the hardware in a reset state. */
-    write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+	write_reg_high(ioaddr, CMR1, CMR1h_RESET);
 
 	return 0;
 }
@@ -774,3 +750,27 @@
  *  tab-width: 4
  * End:
  */
+
+#ifdef MODULE
+
+static int io = 0;
+static char nullname[8] = "";
+static struct net_device atp_dev = {
+	nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_probe };
+	
+MODULE_PARM(io, "I/O port of the pocket adapter");
+
+int init_module(void)
+{
+	atp_dev.base_addr = io;
+	if (register_netdev(&atp_dev) != 0)
+		return -EIO;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev(&atp_dev);
+}
+
+#endif
diff -u --recursive --new-file v2.3.44/linux/drivers/net/atp.h linux/drivers/net/atp.h
--- v2.3.44/linux/drivers/net/atp.h	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/atp.h	Sun Feb 13 18:20:21 2000
@@ -4,15 +4,14 @@
 
 struct net_local 
 {
-#ifdef __KERNEL__
 	struct net_device_stats stats;
-#endif
 	ushort saved_tx_size;
 	unsigned char
 	re_tx,			/* Number of packet retransmissions. */
 	tx_unit_busy,
 	addr_mode,		/* Current Rx filter e.g. promiscuous, etc. */
 	pac_cnt_in_tx_buf;
+	spinlock_t lock;		/* Safety lock */
 };
 
 struct rx_header {
@@ -52,8 +51,7 @@
 	CMR2_h = 0x1d, 
 };
 
-enum eepage_regs
-{ PROM_CMD = 6, PROM_DATA = 7 };	/* Note that PROM_CMD is in the "high" bits. */
+enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 };	/* Note that PROM_CMD is in the "high" bits. */
 
 
 #define ISR_TxOK	0x01
diff -u --recursive --new-file v2.3.44/linux/drivers/net/bmac.c linux/drivers/net/bmac.c
--- v2.3.44/linux/drivers/net/bmac.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/bmac.c	Sun Feb 13 10:47:01 2000
@@ -65,6 +65,7 @@
 	volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
 	volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
 	struct device_node *node;
+	int is_bmac_plus;
 	struct sk_buff *rx_bufs[N_RX_RING];
 	int rx_fill;
 	int rx_empty;
@@ -80,6 +81,7 @@
 	int tx_allocated;
 	unsigned short hash_use_count[64];
 	unsigned short hash_table_mask[4];
+	struct net_device *next_bmac;
 };
 
 typedef struct bmac_reg_entry {
@@ -124,7 +126,6 @@
 };
 
 struct net_device *bmac_devs = NULL;
-static int is_bmac_plus;
 
 #ifdef CONFIG_PMAC_PBOOK
 int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when);
@@ -133,13 +134,6 @@
 };
 #endif
 
-#if 0
-/*
- * If we can't get a skbuff when we need it, we use this area for DMA.
- */
-static unsigned char dummy_buf[RX_BUFLEN];
-#endif
-
 /*
  * Number of bytes of private data per BMAC: allow enough for
  * the rx and tx dma commands plus a branch dma command each,
@@ -151,6 +145,7 @@
 	+ sizeof(struct sk_buff_head))
 
 static unsigned char bitrev(unsigned char b);
+static void bmac_probe1(struct device_node *bmac, int is_bmac_plus);
 static int bmac_open(struct net_device *dev);
 static int bmac_close(struct net_device *dev);
 static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -192,9 +187,10 @@
 void
 dbdma_stop(volatile struct dbdma_regs *dmap)
 {
-	dbdma_st32((volatile unsigned long *)&dmap->control, DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
+	dbdma_st32((volatile unsigned long *)&dmap->control,
+		   DBDMA_CLEAR(RUN) | DBDMA_SET(FLUSH));
 	eieio();
-  
+
 	while (dbdma_ld32((volatile unsigned long *)&dmap->status) & (ACTIVE|FLUSH))
 		eieio();
 }
@@ -210,10 +206,11 @@
 static void
 dbdma_reset(volatile struct dbdma_regs *dmap)
 {
-	dbdma_st32((volatile unsigned long *)&dmap->control, 
-		   DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));      
+	dbdma_st32((volatile unsigned long *)&dmap->control,
+		   DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN));
 	eieio();
-	while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN) eieio();
+	while (dbdma_ld32((volatile unsigned long *)&dmap->status) & RUN)
+		eieio();
 }
 
 static void
@@ -239,7 +236,7 @@
 static __inline__
 volatile unsigned short bmread(struct net_device *dev, unsigned long reg_offset )
 {
-	return in_le16((void *)dev->base_addr + reg_offset); 
+	return in_le16((void *)dev->base_addr + reg_offset);
 }
 
 static void
@@ -248,7 +245,7 @@
 	struct bmac_data *bp = (struct bmac_data *) dev->priv;
 	volatile struct dbdma_regs *rd = bp->rx_dma;
 	volatile struct dbdma_regs *td = bp->tx_dma;
-	 
+
 	dbdma_reset(rd);
 	dbdma_reset(td);
 
@@ -349,7 +346,7 @@
 		regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
 	} while ((regValue & TxResetBit) && i > 0);
 
-	if (!is_bmac_plus) {
+	if (!bp->is_bmac_plus) {
 		regValue = bmread(dev, XCVRIF);
 		regValue |= ClkBit | SerialMode | COLActiveLow;
 		bmwrite(dev, XCVRIF, regValue);
@@ -385,7 +382,7 @@
 
 	/* set rx fifo information */
 	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
-	bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 
+	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
 
 	//bmwrite(dev, TXCFG, TxMACEnable);	       	/* TxNeverGiveUp maybe later */
 	bmread(dev, STATUS);		/* read it just to clear it */
@@ -433,13 +430,13 @@
 
 	/* enable rx dma channel */
 	dbdma_continue(rd);
- 
+
 	oldConfig = bmread(dev, TXCFG);		
-	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
-  
+	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+
 	/* turn on rx plus any other bits already on (promiscuous possibly) */
 	oldConfig = bmread(dev, RXCFG);		
-	bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
+	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
 	udelay(20000);
 }
 
@@ -447,6 +444,7 @@
 bmac_init_phy(struct net_device *dev)
 {
 	unsigned int addr;
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
 
 	printk(KERN_DEBUG "phy registers:");
 	for (addr = 0; addr < 32; ++addr) {
@@ -455,7 +453,7 @@
 		printk(" %.4x", bmac_mif_read(dev, addr));
 	}
 	printk("\n");
-	if (is_bmac_plus) {
+	if (bp->is_bmac_plus) {
 		unsigned int capable, ctrl;
 
 		ctrl = bmac_mif_read(dev, 0);
@@ -622,7 +620,8 @@
 	if (!bp->rx_allocated) {
 		for (i = 0; i < N_RX_RING; i++) {
 			bp->rx_bufs[i] = dev_alloc_skb(RX_BUFLEN+2);
-			if (bp->rx_bufs[i] == NULL) return 0;
+			if (bp->rx_bufs[i] == NULL)
+				return 0;
 			skb_reserve(bp->rx_bufs[i], 2);
 		}
 		bp->rx_allocated = 1;
@@ -657,9 +656,10 @@
 	/* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */
 	/* 	     bp->tx_empty, bp->tx_fill)); */
 	i = bp->tx_fill + 1;
-	if (i >= N_TX_RING) i = 0;
+	if (i >= N_TX_RING)
+		i = 0;
 	if (i == bp->tx_empty) {
-		dev->tbusy = 1;
+		netif_stop_queue(dev);
 		bp->tx_fullup = 1;
 		XXDEBUG(("bmac_transmit_packet: tx ring full\n"));
 		return -1;		/* can't take it at the moment */
@@ -776,16 +776,15 @@
 
 		if (bp->tx_bufs[bp->tx_empty]) {
 			++bp->stats.tx_packets;
-			dev_kfree_skb(bp->tx_bufs[bp->tx_empty]);
+			dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]);
 		}
 		bp->tx_bufs[bp->tx_empty] = NULL;
 		bp->tx_fullup = 0;
-		dev->tbusy = 0;
-		/* XXDEBUG(("bmac_intr: cleared tbusy, empty=%d fill=%d\n", */
-		/* 		 i, bp->tx_fill)); */
-		mark_bh(NET_BH);
-		if (++bp->tx_empty >= N_TX_RING) bp->tx_empty = 0;
-		if (bp->tx_empty == bp->tx_fill) break;
+		netif_wake_queue(dev);
+		if (++bp->tx_empty >= N_TX_RING)
+			bp->tx_empty = 0;
+		if (bp->tx_empty == bp->tx_fill)
+			break;
 	}
 
 	restore_flags(flags);
@@ -831,7 +830,7 @@
 		/* is high CRC bit set? */
 		if ((cur & 0x80000000) == 0) high_crc_set = 0;
 		else high_crc_set = 1;
-      
+
 		cur = cur << 1;
 	
 		if ((next & 0x0001) == 0) low_data_set = 0;
@@ -859,8 +858,8 @@
 }
 
 /*
- * Add requested mcast addr to BMac's hash table filter.  
- *  
+ * Add requested mcast addr to BMac's hash table filter.
+ *
  */
 
 static void
@@ -925,7 +924,7 @@
 	else rx_cfg &= ~RxPromiscEnable;
 	bmwrite(dev, RXRST, RxResetValue);
 	bmwrite(dev, RXFIFOCSR, 0);	/* first disable rxFIFO */
-	bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 
+	bmwrite(dev, RXFIFOCSR, RxFIFOEnable );
 	bmwrite(dev, RXCFG, rx_cfg );
 	return rx_cfg;
 }
@@ -1020,13 +1019,7 @@
 	int i, j, bit, byte;
 	unsigned short rx_cfg;
 	u32 crc, poly = CRC_POLYNOMIAL_LE;
-    
-	/* Let the transmits drain. */
-	/*     while(dev->tbusy) schedule(); */
-    
-	/* Lock out others. */
-	/*     set_bit(0, (void *) &dev->tbusy); */
-    
+
 	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
 		bmwrite(dev, BHASH0, 0xffff);
 		bmwrite(dev, BHASH1, 0xffff);
@@ -1048,15 +1041,15 @@
 		for(i = 0; i < dev->mc_count; i++) {
 			addrs = dmi->dmi_addr;
 			dmi = dmi->next;
-	    
+
 			if(!(*addrs & 1))
 				continue;
-	    
+
 			crc = 0xffffffffU;
 			for(byte = 0; byte < 6; byte++) {
 				for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
 					int test;
-		    
+
 					test = ((bit ^ crc) & 0x01);
 					crc >>= 1;
 					if(test)
@@ -1071,9 +1064,6 @@
 		bmwrite(dev, BHASH2, hash_table[2]);
 		bmwrite(dev, BHASH3, hash_table[3]);
 	}
-    
-	/* Let us get going again. */
-	/*     dev->tbusy = 0; */
 }
 #endif /* SUNHME_MULTICAST */
 
@@ -1103,7 +1093,7 @@
 }
 
 /*
- * Procedure for reading EEPROM 
+ * Procedure for reading EEPROM
  */
 #define SROMAddressLength	5
 #define DataInOn		0x0008
@@ -1126,28 +1116,28 @@
 
 	bmwrite(dev, SROMCSR, ChipSelect | Clk);
 	udelay(DelayValue);
-    
+
 	data = bmread(dev, SROMCSR);
 	udelay(DelayValue);
 	val = (data >> SD0ShiftCount) & 1;
 
 	bmwrite(dev, SROMCSR, ChipSelect);
 	udelay(DelayValue);
-    
+
 	return val;
 }
 
 static void
 bmac_clock_in_bit(struct net_device *dev, unsigned int val)
 {
-	unsigned short		data;    
+	unsigned short data;
 
 	if (val != 0 && val != 1) return;
-    
+
 	data = (val << SDIShiftCount);
 	bmwrite(dev, SROMCSR, data | ChipSelect  );
 	udelay(DelayValue);
-    
+
 	bmwrite(dev, SROMCSR, data | ChipSelect | Clk );
 	udelay(DelayValue);
 
@@ -1161,7 +1151,7 @@
 	/* first reset */
 	bmwrite(dev, SROMCSR, 0);
 	udelay(DelayValue);
-    
+
 	/* send it the read command (110) */
 	bmac_clock_in_bit(dev, 1);
 	bmac_clock_in_bit(dev, 1);
@@ -1173,13 +1163,13 @@
 {
 	unsigned short data, val;
 	int i;
-    
+
 	/* send out the address we want to read from */
 	for (i = 0; i < addr_len; i++)	{
 		val = addr >> (addr_len-i-1);
 		bmac_clock_in_bit(dev, val & 1);
 	}
-    
+
 	/* Now read in the 16-bit data */
 	data = 0;
 	for (i = 0; i < 16; i++)	{
@@ -1188,24 +1178,24 @@
 		data |= val;
 	}
 	bmwrite(dev, SROMCSR, 0);
-    
+
 	return data;
 }
 
 /*
  * It looks like Cogent and SMC use different methods for calculating
- * checksums. What a pain.. 
+ * checksums. What a pain..
  */
 
 static int
 bmac_verify_checksum(struct net_device *dev)
 {
 	unsigned short data, storedCS;
-    
+
 	reset_and_select_srom(dev);
 	data = read_srom(dev, 3, SROMAddressBits);
 	storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00);
-    
+
 	return 0;
 }
 
@@ -1236,8 +1226,10 @@
 	bp->reset_and_enabled = 0;
 	bmac_reset_chip(dev);
 	if (enable) {
-		if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp)) return 0;
-		if (!bmac_init_chip(dev)) return 0;
+		if (!bmac_init_tx_ring(bp) || !bmac_init_rx_ring(bp))
+			return 0;
+		if (!bmac_init_chip(dev))
+			return 0;
 		bmac_start_chip(dev);
 		bmwrite(dev, INTDISABLE, EnableNormal);
 		bp->reset_and_enabled = 1;
@@ -1257,70 +1249,55 @@
 	return 1;
 }
 
-static int __init bmac_probe (void)
+static int __init bmac_probe(void)
 {
-	int j, rev;
-	struct bmac_data *bp;
-	struct device_node *bmacs;
-	unsigned char *addr;
-	static struct device_node *all_bmacs = NULL, *next_bmac;
-	struct net_device *dev = NULL;
+	struct device_node *bmac;
 
-#ifdef MODULE
-	if(bmac_devs != NULL)
-		return -EBUSY;
-#endif
+	for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next)
+		bmac_probe1(bmac, 0);
+	for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0;
+	     bmac = bmac->next)
+		bmac_probe1(bmac, 1);
 
-	if (all_bmacs == NULL) {
-		all_bmacs = find_devices("bmac");
-		is_bmac_plus = 0;
-		if (all_bmacs == NULL) {
-			all_bmacs = find_compatible_devices("network", "bmac+");
-			if (all_bmacs)
-				is_bmac_plus = 1;
-		}
-		next_bmac = all_bmacs;
-	}
-	bmacs = next_bmac;
-	if (bmacs == NULL) return -ENODEV;
-	next_bmac = bmacs->next;
-
-	if (bmac_devs == 0) {
-		bmac_devs = dev; /* KLUDGE!! */
+	if (bmac_devs != 0) {
+		proc_net_create ("bmac", 0, bmac_proc_info);
 #ifdef CONFIG_PMAC_PBOOK
 		pmu_register_sleep_notifier(&bmac_sleep_notifier);
 #endif
 	}
+	return 0;
+}
 
-	if (bmacs->n_addrs != 3 || bmacs->n_intrs != 3) {
-		printk(KERN_ERR "can't use BMAC %s: expect 3 addrs and 3 intrs\n",
-		       bmacs->full_name);
-		return -EINVAL;
+static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
+{
+	int j, rev;
+	struct bmac_data *bp;
+	unsigned char *addr;
+	struct net_device *dev;
+
+	if (bmac->n_addrs != 3 || bmac->n_intrs != 3) {
+		printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n",
+		       bmac->full_name);
+		return;
+	}
+	addr = get_property(bmac, "mac-address", NULL);
+	if (addr == NULL) {
+		addr = get_property(bmac, "local-mac-address", NULL);
+		if (addr == NULL) {
+			printk(KERN_ERR "Can't get mac-address for BMAC %s\n",
+			       bmac->full_name);
+			return;
+		}
 	}
 
 	dev = init_etherdev(NULL, PRIV_BYTES);
-	bmac_devs = dev;  /*KLUDGE!!*/
 
-#ifdef MODULE
-	bmac_devs = dev;
-#endif
-    
 	dev->base_addr = (unsigned long)
-		ioremap(bmacs->addrs[0].address, bmacs->addrs[0].size);
-	dev->irq = bmacs->intrs[0].line;
+		ioremap(bmac->addrs[0].address, bmac->addrs[0].size);
+	dev->irq = bmac->intrs[0].line;
 
 	bmwrite(dev, INTDISABLE, DisableAll);
-    
-	addr = get_property(bmacs, "mac-address", NULL);
-	if (addr == NULL) {
-		addr = get_property(bmacs, "local-mac-address", NULL);
-		if (addr == NULL) {
-			printk(KERN_ERR "Can't get mac-address for BMAC at %lx\n",
-			       dev->base_addr);
-			return -EAGAIN;
-		}
-	}
-    
+
 	printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
 	rev = addr[0] == 0 && addr[1] == 0xA0;
 	for (j = 0; j < 6; ++j) {
@@ -1329,7 +1306,7 @@
 	}
 	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
 	printk("\n");
-    
+
 	dev->open = bmac_open;
 	dev->stop = bmac_close;
 	dev->hard_start_xmit = bmac_output;
@@ -1338,61 +1315,55 @@
 	dev->set_mac_address = bmac_set_address;
 
 	bmac_get_station_address(dev, addr);
-	if (bmac_verify_checksum(dev) != 0) return -EINVAL;
-    
+	if (bmac_verify_checksum(dev) != 0)
+		return;
+
 	ether_setup(dev);
-    
+
 	bp = (struct bmac_data *) dev->priv;
 	memset(bp, 0, sizeof(struct bmac_data));
+	bp->is_bmac_plus = is_bmac_plus;
 	bp->tx_dma = (volatile struct dbdma_regs *)
-		ioremap(bmacs->addrs[1].address, bmacs->addrs[1].size);
-	bp->tx_dma_intr = bmacs->intrs[1].line;
+		ioremap(bmac->addrs[1].address, bmac->addrs[1].size);
+	bp->tx_dma_intr = bmac->intrs[1].line;
 	bp->rx_dma = (volatile struct dbdma_regs *)
-		ioremap(bmacs->addrs[2].address, bmacs->addrs[2].size);
-	bp->rx_dma_intr = bmacs->intrs[2].line;
-    
+		ioremap(bmac->addrs[2].address, bmac->addrs[2].size);
+	bp->rx_dma_intr = bmac->intrs[2].line;
+
 	bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
 	bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
 
 	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
 	skb_queue_head_init(bp->queue);
-    
-	bp->node = bmacs;
+
+	bp->node = bmac;
 	memset(&bp->stats, 0, sizeof(bp->stats));
 	memset((char *) bp->tx_cmds, 0,
 	       (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
 	/*     init_timer(&bp->tx_timeout); */
 	/*     bp->timeout_active = 0; */
 
-	if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev)) {
+	if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev))
 		printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
-		return -EAGAIN;
-	}
-	if (request_irq(bmacs->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
-			dev)) {
-		printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[1].line);
-		return -EAGAIN;
-	}
-	if (request_irq(bmacs->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
-			dev)) {
-		printk(KERN_ERR "BMAC: can't get irq %d\n", bmacs->intrs[2].line);
-		return -EAGAIN;
-	}
-    
-	if (!bmac_reset_and_enable(dev, 0)) return -ENOMEM;
-    
-	proc_net_create ("bmac", 0, bmac_proc_info);
+	if (request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
+			dev))
+		printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line);
+	if (request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
+			dev))
+		printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line);
 
-	return 0;
+	bp->next_bmac = bmac_devs;
+	bmac_devs = dev;
 }
 
 static int bmac_open(struct net_device *dev)
 {
 	/* XXDEBUG(("bmac: enter open\n")); */
 	/* reset the chip */
-	bmac_reset_and_enable(dev, 1);
+	if (!bmac_reset_and_enable(dev, 1))
+		return -ENOMEM;
 
-	dev->flags |= IFF_UP | IFF_RUNNING;
+	dev->flags |= IFF_RUNNING;
 
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -1452,14 +1423,17 @@
 	int i;
 	struct sk_buff *skb;
 	unsigned long flags;
-    
+
 	save_flags(flags); cli();
 	while (1) {
 		i = bp->tx_fill + 1;
-		if (i >= N_TX_RING) i = 0;
-		if (i == bp->tx_empty) break;
+		if (i >= N_TX_RING)
+			i = 0;
+		if (i == bp->tx_empty)
+			break;
 		skb = skb_dequeue(bp->queue);
-		if (skb == NULL) break;
+		if (skb == NULL)
+			break;
 		bmac_transmit_packet(skb, dev);
 	}
 	restore_flags(flags);
@@ -1525,9 +1499,7 @@
 		bp->tx_empty = i;
 	}
 	bp->tx_fullup = 0;
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
-	XXDEBUG((KERN_DEBUG "bmac: clearing tbusy\n"));
+	netif_wake_queue(dev);
 	if (i != bp->tx_fill) {
 		cp = &bp->tx_cmds[i];
 		out_le16(&cp->xfer_status, 0);
@@ -1540,9 +1512,9 @@
 
 	/* turn it back on */
 	oldConfig = bmread(dev, RXCFG);		
-	bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 
+	bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
 	oldConfig = bmread(dev, TXCFG);		
-	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );  
+	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
 
 	restore_flags(flags);
 }
@@ -1573,7 +1545,8 @@
 	off_t begin = 0;
 	int i;
 
-	if (bmac_devs == NULL) return (-ENOSYS);
+	if (bmac_devs == NULL)
+		return (-ENOSYS);
 
 	len += sprintf(buffer, "BMAC counters & registers\n");
 
@@ -1582,20 +1555,20 @@
 			       reg_entries[i].name,
 			       bmread(bmac_devs, reg_entries[i].reg_offset));
 		pos = begin + len;
-    
+
 		if (pos < offset) {
 			len = 0;
 			begin = pos;
 		}
-    
+
 		if (pos > offset+length) break;
 	}
-  
+
 	*start = buffer + (offset - begin);
 	len -= (offset - begin);
-  
+
 	if (len > length) len = length;
-  
+
 	return len;
 }
 
@@ -1606,26 +1579,28 @@
 
 static void __exit bmac_cleanup (void)
 {
-#ifdef MODULE
-    struct bmac_data *bp;
-
-    if (bmac_devs == 0)
-	return;
-
-    bp = (struct bmac_data *) bmac_devs->priv;
-    unregister_netdev(bmac_devs);
-    proc_net_remove("bmac");
-
-    free_irq(bmac_devs->irq, bmac_misc_intr);
-    free_irq(bp->tx_dma_intr, bmac_txdma_intr);
-    free_irq(bp->rx_dma_intr, bmac_rxdma_intr);
+	struct bmac_data *bp;
+	struct net_device *dev;
 
+	if (bmac_devs == 0)
+		return;
 #ifdef CONFIG_PMAC_PBOOK
-    pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
-#endif
-    kfree(bmac_devs);
-    bmac_devs = NULL;
+	pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
 #endif
+	proc_net_remove("bmac");
+
+	do {
+		dev = bmac_devs;
+		bp = (struct bmac_data *) dev->priv;
+		bmac_devs = bp->next_bmac;
+
+		free_irq(dev->irq, dev);
+		free_irq(bp->tx_dma_intr, dev);
+		free_irq(bp->rx_dma_intr, dev);
+
+		unregister_netdev(dev);
+		kfree(dev);
+	} while (bmac_devs != NULL);
 }
 
 module_init(bmac_probe);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.44/linux/drivers/net/de4x5.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/de4x5.c	Sat Feb 12 15:44:09 2000
@@ -1761,7 +1761,7 @@
     pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf),
 		     le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1);
     if ((u_long) lp->tx_skb[entry] > 1)
-	dev_kfree_skb(lp->tx_skb[entry]);
+	dev_kfree_skb_irq(lp->tx_skb[entry]);
     lp->tx_skb[entry] = NULL;
 }
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.3.44/linux/drivers/net/defxx.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/defxx.c	Sun Feb 13 18:20:21 2000
@@ -253,7 +253,7 @@
 
 static void		dfx_int_pr_halt_id(DFX_board_t *bp);
 static void		dfx_int_type_0_process(DFX_board_t *bp);
-static void		dfx_int_common(DFX_board_t *bp);
+static void		dfx_int_common(struct net_device *dev);
 static void		dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 static struct		net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
@@ -272,7 +272,7 @@
 static void		dfx_rcv_queue_process(DFX_board_t *bp);
 
 static int		dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static void		dfx_xmt_done(DFX_board_t *bp);
+static int		dfx_xmt_done(DFX_board_t *bp);
 static void		dfx_xmt_flush(DFX_board_t *bp);
 
 /* Define module-wide (static) variables */
@@ -1423,9 +1423,7 @@
 
 	/* Set device structure info */
 
-	dev->tbusy			= 0;
-	dev->interrupt		= DFX_UNMASK_INTERRUPTS;
-	dev->start			= 1;
+	netif_start_queue(dev);
 	return(0);
 	}
 
@@ -1511,9 +1509,8 @@
 
 	/* Clear device structure flags */
 
-	dev->start = 0;
-	dev->tbusy = 1;
-
+	netif_stop_queue(dev);
+	
 	/* Deregister (free) IRQ */
 
 	free_irq(dev->irq, dev);
@@ -1804,16 +1801,15 @@
  *   or updating completion indices.
  */
 
-void dfx_int_common(
-	DFX_board_t	*bp
-	)
-
-	{
+void dfx_int_common(struct net_device *dev)
+{
+	DFX_board_t 	*bp = (DFX_board_t *) dev->priv;
 	PI_UINT32	port_status;		/* Port Status register */
 
 	/* Process xmt interrupts - frequent case, so always call this routine */
 
-	dfx_xmt_done(bp);				/* free consumed xmt packets */
+	if(dfx_xmt_done(bp))				/* free consumed xmt packets */
+		netif_wake_queue(dev);
 
 	/* Process rcv interrupts - frequent case, so always call this routine */
 
@@ -1889,21 +1885,12 @@
 
 	/* Get board pointer only if device structure is valid */
 
-	if (dev == NULL)
-		{
-		printk("dfx_interrupt(): irq %d for unknown device!\n", irq);
-		return;
-		}
 	bp = (DFX_board_t *) dev->priv;
 
 	spin_lock(&bp->lock);
 	
 	/* See if we're already servicing an interrupt */
 
-	if (dev->interrupt)
-		printk("%s: Re-entering the interrupt handler!\n", dev->name);
-	dev->interrupt = DFX_MASK_INTERRUPTS;	/* ensure non reentrancy */
-
 	/* Service adapter interrupts */
 
 	if (bp->bus_type == DFX_BUS_TYPE_PCI)
@@ -1914,7 +1901,7 @@
 
 		/* Call interrupt service routine for this adapter */
 
-		dfx_int_common(bp);
+		dfx_int_common(dev);
 
 		/* Clear PDQ interrupt status bit and reenable interrupts */
 
@@ -1932,7 +1919,7 @@
 
 		/* Call interrupt service routine for this adapter */
 
-		dfx_int_common(bp);
+		dfx_int_common(dev);
 
 		/* Reenable interrupts at the ESIC */
 
@@ -1941,7 +1928,6 @@
 		dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
 		}
 
-	dev->interrupt = DFX_UNMASK_INTERRUPTS;
 	spin_unlock(&bp->lock);
 	return;
 	}
@@ -3199,6 +3185,8 @@
 	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
 	unsigned long		flags;
 
+	netif_stop_queue(dev);
+	
 	/*
 	 * Verify that incoming transmit request is OK
 	 *
@@ -3213,7 +3201,7 @@
 		printk("%s: Invalid packet length - %u bytes\n", 
 			dev->name, skb->len);
 		bp->xmt_length_errors++;		/* bump error counter */
-		mark_bh(NET_BH);
+		netif_wake_queue(dev);
 		dev_kfree_skb(skb);
 		return(0);				/* return "success" */
 	}
@@ -3237,6 +3225,7 @@
 			{
 			bp->xmt_discards++;					/* bump error counter */
 			dev_kfree_skb(skb);		/* free sk_buff now */
+			netif_wake_queue(dev);
 			return(0);							/* return "success" */
 			}
 		}
@@ -3339,6 +3328,7 @@
 	bp->rcv_xmt_reg.index.xmt_prod = prod;
 	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
 	spin_unlock_irqrestore(&bp->lock, flags);
+	netif_wake_queue(dev);
 	return(0);							/* packet queued to adapter */
 	}
 
@@ -3375,13 +3365,14 @@
  *   None
  */
 
-void dfx_xmt_done(
+int dfx_xmt_done(
 	DFX_board_t *bp
 	)
 
 	{
 	XMT_DRIVER_DESCR	*p_xmt_drv_descr;	/* ptr to transmit driver descriptor */
 	PI_TYPE_2_CONSUMER	*p_type_2_cons;		/* ptr to rcv/xmt consumer block register */
+	int 			freed = 0;		/* buffers freed */
 
 	/* Service all consumed transmit frames */
 
@@ -3413,8 +3404,9 @@
 		 */
 
 		bp->rcv_xmt_reg.index.xmt_comp += 1;
+		freed++;
 		}
-	return;
+	return freed;
 	}
 
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.44/linux/drivers/net/eepro100.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/eepro100.c	Sun Feb 13 18:24:12 2000
@@ -1,7 +1,9 @@
-/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
 /*
-   NOTICE: this version tested with kernels 1.3.72 and later only!
+
+	 drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux
+
 	Written 1996-1999 by Donald Becker.
+	Modified 2000 by Linux Kernel Team
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -20,132 +22,15 @@
 		http://cesdis.gsfc.nasa.gov/linux/misc/modules.html
 	There is a Majordomo mailing list based at
 		linux-eepro100@cesdis.gsfc.nasa.gov
-*/
 
-static const char *version =
-"eepro100.c:v1.09j 7/27/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
 
-/* A few user-configurable values that apply to all boards.
-   First set is undocumented and spelled per Intel recommendations. */
 
-static int congenb = 0;		/* Enable congestion control in the DP83840. */
-static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
-static int rxfifo = 8;		/* Rx FIFO threshold, default 32 bytes. */
-/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
-static int txdmacount = 128;
-static int rxdmacount = 0;
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
-   Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
+   Version history:
+   	v1.09j+LK1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
+		Convert to new PCI driver interface
 
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
 
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
 
-/* 'options' is used to pass a transceiver override or full-duplex flag
-   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1;			/* The debug level */
-
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE	32		/* Effectively 2 entries fewer. */
-#define RX_RING_SIZE	32
-/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
-#define TX_QUEUE_LIMIT  12
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ		1536
-
-#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
-#warning  You must compile this file with the correct options!
-#warning  See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
-#include <linux/version.h>
-#include <linux/module.h>
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#ifdef HAS_PCI_NETIF
-#include "pci-netif.h"
-#else
-#include <linux/pci.h>
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h>		/* Ignore the bogus warning in 2.1.100+ */
-#endif
-#endif
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(multicast_filter_limit, "i");
-
-#define RUN_AT(x) (jiffies + (x))
-
-#if (LINUX_VERSION_CODE < 0x20123)
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#define le16_to_cpu(val) (val)
-#define cpu_to_le16(val) (val)
-#define le32_to_cpu(val) (val)
-#define cpu_to_le32(val) (val)
-#define spin_lock_irqsave(&sp->lock, flags)	save_flags(flags); cli();
-#define spin_unlock_irqrestore(&sp->lock, flags); restore_flags(flags);
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
-#if ! defined(CAP_NET_ADMIN)
-#define capable(CAP_XXX) (suser())
-#endif
-#if ! defined(HAS_NETIF_QUEUE)
-#define netif_wake_queue(dev)  mark_bh(NET_BH);
-#endif
-
-/* The total I/O port extent of the board.
-   The registers beyond 0x18 only exist on the i82558. */
-#define SPEEDO3_TOTAL_SIZE 0x20
-
-int speedo_debug = 1;
-
-/*
 				Theory of Operation
 
 I. Board Compatibility
@@ -277,40 +162,108 @@
 
 */
 
-/* This table drives the PCI probe routines. */
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
 
-#ifdef USE_IO
-#define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
-#define SPEEDO_SIZE		32
-#else
-#define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
-#define SPEEDO_SIZE		0x1000
+static const char *version =
+"eepro100.c:v1.09j+LK1.0 Feb 13, 2000  Linux Kernel Team  http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
+
+/* A few user-configurable values that apply to all boards.
+   First set is undocumented and spelled per Intel recommendations. */
+
+static int congenb = 0;		/* Enable congestion control in the DP83840. */
+static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
+static int rxfifo = 8;		/* Rx FIFO threshold, default 32 bytes. */
+/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
+static int txdmacount = 128;
+static int rxdmacount = 0;
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
+   Lower values use more memory, but are faster. */
+static int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
+/* 'options' is used to pass a transceiver override or full-duplex flag
+   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+#if MODULE_SETUP_FIXED
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #endif
+static int debug = -1;			/* The debug level */
+
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE	32		/* Effectively 2 entries fewer. */
+#define RX_RING_SIZE	32
+/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
+#define TX_QUEUE_LIMIT  12
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ		1536
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+
+#if MODULE_OPTIONS_FIXED
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+#endif
+
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
+
+#define EEPRO100_MODULE_NAME "eepro100"
+#define PFX EEPRO100_MODULE_NAME ": "
+
+#define RUN_AT(x) (jiffies + (x))
+
+int speedo_debug = 1;
+
 
-#if defined(HAS_PCI_NETIF)
-struct pci_id_info static pci_tbl[] = {
-	{ "Intel PCI EtherExpress Pro100",
-	  { 0x12298086, 0xffffffff,}, SPEEDO_IOTYPE, SPEEDO_SIZE,
-	  0, speedo_found1 },
-	{0,},						/* 0 terminated list. */
-};
-#else
 enum pci_flags_bit {
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
-struct pci_id_info {
-	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
-	int io_size;
-	struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-} static pci_tbl[] = {
-	{ "Intel PCI EtherExpress Pro100",
-	  0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 },
-	{0,},						/* 0 terminated list. */
-};
-#endif
 
 #ifndef USE_IO
 #define inb readb
@@ -362,54 +315,75 @@
 #endif
 
 enum SCBCmdBits {
-     SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
-     SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
-     SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
-     /* The rest are Rx and Tx commands. */
-     CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
-     CUCmdBase=0x0060,  /* CU Base address (set to zero) . */
-     CUDumpStats=0x0070, /* Dump then reset stats counters. */
-     RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
-     RxResumeNoResources=0x0007,
+	SCBMaskCmdDone = 0x8000,
+	SCBMaskRxDone = 0x4000,
+	SCBMaskCmdIdle = 0x2000,
+	SCBMaskRxSuspend = 0x1000,
+	SCBMaskEarlyRx = 0x0800,
+	SCBMaskFlowCtl = 0x0400,
+	SCBTriggerIntr = 0x0200,
+	SCBMaskAll = 0x0100,
+	/* The rest are Rx and Tx commands. */
+	CUStart = 0x0010,
+	CUResume = 0x0020,
+	CUStatsAddr = 0x0040,
+	CUShowStats = 0x0050,
+	CUCmdBase = 0x0060,	/* CU Base address (set to zero) . */
+	CUDumpStats = 0x0070,	/* Dump then reset stats counters. */
+	RxStart = 0x0001,
+	RxResume = 0x0002,
+	RxAbort = 0x0004,
+	RxAddrLoad = 0x0006,
+	RxResumeNoResources = 0x0007,
 };
 
 enum SCBPort_cmds {
-	PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
+	PortReset = 0,
+	PortSelfTest = 1,
+	PortPartialReset = 2,
+	PortDump = 3,
 };
 
 /* The Speedo3 Rx and Tx frame/buffer descriptors. */
-struct descriptor {			/* A generic descriptor. */
-	s32 cmd_status;			/* All command and status fields. */
-	u32 link;					/* struct descriptor *  */
+struct descriptor {		/* A generic descriptor. */
+	s32 cmd_status;		/* All command and status fields. */
+	u32 link;		/* struct descriptor *  */
 	unsigned char params[0];
 };
 
 /* The Speedo3 Rx and Tx buffer descriptors. */
-struct RxFD {					/* Receive frame descriptor. */
+struct RxFD {			/* Receive frame descriptor. */
 	s32 status;
-	u32 link;					/* struct RxFD * */
-	u32 rx_buf_addr;			/* void * */
+	u32 link;		/* struct RxFD * */
+	u32 rx_buf_addr;	/* void * */
 	u32 count;
 };
 
 /* Selected elements of the Tx/RxFD.status word. */
 enum RxFD_bits {
-	RxComplete=0x8000, RxOK=0x2000,
-	RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
-	RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
-	TxUnderrun=0x1000,  StatusComplete=0x8000,
+	RxComplete = 0x8000,
+	RxOK = 0x2000,
+	RxErrCRC = 0x0800,
+	RxErrAlign = 0x0400,
+	RxErrTooBig = 0x0200,
+	RxErrSymbol = 0x0010,
+	RxEth2Type = 0x0020,
+	RxNoMatch = 0x0004,
+	RxNoIAMatch = 0x0002,
+	TxUnderrun = 0x1000,
+	StatusComplete = 0x8000,
 };
 
-struct TxFD {					/* Transmit frame descriptor set. */
+struct TxFD {			/* Transmit frame descriptor set. */
 	s32 status;
-	u32 link;					/* void * */
-	u32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
-	s32 count;					/* # of TBD (=1), Tx start thresh., etc. */
+	u32 link;		/* void * */
+	u32 tx_desc_addr;	/* Always points to the tx_buf_addr element. */
+	s32 count;		/* # of TBD (=1), Tx start thresh., etc. */
 	/* This constitutes two "TBD" entries -- we only use one. */
-	u32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size0;			/* Length of Tx frame. */
-	u32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size1;			/* Length of Tx frame. */
+	u32 tx_buf_addr0;	/* void *, frame to be transmitted.  */
+	s32 tx_buf_size0;	/* Length of Tx frame. */
+	u32 tx_buf_addr1;	/* void *, frame to be transmitted.  */
+	s32 tx_buf_size1;	/* Length of Tx frame. */
 };
 
 /* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -436,46 +410,43 @@
 /* Do not change the position (alignment) of the first few elements!
    The later elements are grouped for cache locality. */
 struct speedo_private {
-	struct TxFD	*tx_ring;		/* Commands (usually CmdTxPacket). */
-	struct RxFD *rx_ringp[RX_RING_SIZE];	/* Rx descriptor, used as ring. */
+	struct TxFD *tx_ring;		/* Commands (usually CmdTxPacket). */
+	struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
 	/* The addresses of a Tx/Rx-in-place packets/buffers. */
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-	dma_addr_t	rx_ring_dma[RX_RING_SIZE];
-	dma_addr_t	tx_ring_dma;
-	struct descriptor  *last_cmd;	/* Last command sent. */
+	struct sk_buff *tx_skbuff[TX_RING_SIZE];
+	struct sk_buff *rx_skbuff[RX_RING_SIZE];
+	dma_addr_t rx_ring_dma[RX_RING_SIZE];
+	dma_addr_t tx_ring_dma;
+	struct descriptor *last_cmd;	/* Last command sent. */
 	unsigned int cur_tx, dirty_tx;	/* The ring entries to be free()ed. */
-	spinlock_t lock;				/* Group with Tx control cache line. */
-	u32 tx_threshold;					/* The value for txdesc.count. */
-	struct RxFD *last_rxf;	/* Last command sent. */
-	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
-	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
+	spinlock_t lock;		/* Group with Tx control cache line. */
+	u32 tx_threshold;		/* The value for txdesc.count. */
+	struct RxFD *last_rxf;		/* Last command sent. */
+	unsigned int cur_rx, dirty_rx;	/* The next free ring entry */
+	long last_rx_time;		/* Last Rx, in jiffies, to handle Rx hang. */
 	const char *product_name;
-	struct net_device *next_module;
-	void *priv_addr;					/* Unaligned address for kfree */
 	struct enet_statistics stats;
 	struct speedo_stats *lstats;
 	int chip_id;
-	unsigned char pci_bus, pci_devfn, acpi_pwr;
+	unsigned char acpi_pwr;
 	struct pci_dev *pdev;
 	struct timer_list timer;	/* Media selection timer. */
-	int mc_setup_frm_len;			 	/* The length of an allocated.. */
-	struct descriptor *mc_setup_frm; 	/* ..multicast setup frame. */
-	int mc_setup_busy;					/* Avoid double-use of setup frame. */
+	int mc_setup_frm_len;		/* The length of an allocated.. */
+	struct descriptor *mc_setup_frm;/* ..multicast setup frame. */
+	int mc_setup_busy;		/* Avoid double-use of setup frame. */
 	dma_addr_t mc_setup_dma;
-	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int flow_ctrl:1;			/* Use 802.3x flow control. */
-	unsigned int rx_bug:1;				/* Work around receiver hang errata. */
-	unsigned int rx_bug10:1;			/* Receiver might hang at 10mbps. */
-	unsigned int rx_bug100:1;			/* Receiver might hang at 100mbps. */
-	unsigned char default_port:8;		/* Last dev->if_port value. */
-	unsigned short phy[2];				/* PHY media interfaces available. */
-	unsigned short advertising;			/* Current PHY advertised caps. */
-	unsigned short partner;				/* Link partner caps. */
+	char rx_mode;			/* Current PROMISC/ALLMULTI setting. */
+	unsigned int tx_full:1;		/* The Tx queue is full. */
+	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
+	unsigned int flow_ctrl:1;	/* Use 802.3x flow control. */
+	unsigned int rx_bug:1;		/* Work around receiver hang errata. */
+	unsigned int rx_bug10:1;	/* Receiver might hang at 10mbps. */
+	unsigned int rx_bug100:1;	/* Receiver might hang at 100mbps. */
+	unsigned char default_port:8;	/* Last dev->if_port value. */
+	unsigned short phy[2];		/* PHY media interfaces available. */
+	unsigned short advertising;	/* Current PHY advertised caps. */
+	unsigned short partner;		/* Link partner caps. */
 };
-
 /* The parameters for a CmdConfigure operation.
    There are so many options that it would be difficult to document each bit.
    We mostly use the default or recommended settings. */
@@ -526,151 +497,93 @@
 						   0x2000, 0x2100, 0x0400, 0x3100};
 #endif
 
-/* A list of all installed Speedo devices, for removing the driver module. */
-static struct net_device *root_speedo_dev = NULL;
-
-#if ! defined(HAS_PCI_NETIF)
-int eepro100_init(void)
-{
-	int cards_found = 0;
-	static int pci_index = 0;
-
-	if (! pcibios_present())
-		return cards_found;
-
-	for (; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn, pci_latency;
-		long ioaddr;
-		int irq;
-
-		u16 pci_command, new_command;
-
-		if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
-								PCI_DEVICE_ID_INTEL_82557,
-								pci_index, &pci_bus,
-								&pci_device_fn))
-			break;
-#if LINUX_VERSION_CODE >= 0x20155  ||  PCI_SUPPORT_1
-		{
-			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-#ifdef USE_IO
-			ioaddr = pdev->resource[1].start;
-#else
-			ioaddr = pdev->resource[0].start;
-#endif
-			irq = pdev->irq;
-		}
-#else
-		{
-			u32 pciaddr;
-			u8 pci_irq_line;
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_INTERRUPT_LINE, &pci_irq_line);
-			/* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
-#ifdef USE_IO
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_1, &pciaddr);
-			pciaddr &= ~3UL;
-#else
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_0, &pciaddr);
-#endif
-			ioaddr = pciaddr;
-			irq = pci_irq_line;
-		}
-#endif
-		/* Remove I/O space marker in bit 0. */
-#ifdef USE_IO
-		if (check_region(ioaddr, 32))
-			continue;
-#else
-		{
-			unsigned long orig_ioaddr = ioaddr;
-
-			if ((ioaddr = (long)ioremap(ioaddr & ~0xfUL, 0x1000)) == 0) {
-				printk(KERN_INFO "Failed to map PCI address %#lx.\n",
-					   orig_ioaddr);
-				continue;
-			}
-		}
-#endif
-		if (speedo_debug > 2)
-			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
-				   ioaddr, irq);
-
-		/* Get and check the bus-master and latency values. */
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_COMMAND, &pci_command);
-		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled this"
-				   " device!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-									  PCI_COMMAND, new_command);
-		}
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-								 PCI_LATENCY_TIMER, &pci_latency);
-		if (pci_latency < 32) {
-			printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-				   "  Setting to 32 clocks.\n", pci_latency);
-			pcibios_write_config_byte(pci_bus, pci_device_fn,
-									  PCI_LATENCY_TIMER, 32);
-		} else if (speedo_debug > 1)
-			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
-
-		if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0,cards_found))
-			cards_found++;
-	}
 
-	return cards_found;
-}
-#endif
 
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn, 
-			  long ioaddr, int irq, int chip_idx, int card_idx)
+static int __devinit eepro100_init_one (struct pci_dev *pdev,
+				        const struct pci_device_id *ent)
 {
 	struct net_device *dev;
 	struct speedo_private *sp;
-	struct pci_dev *pdev;
 	unsigned char *tx_ring;
 	dma_addr_t tx_ring_dma;
 	const char *product;
 	int i, option;
 	u16 eeprom[0x100];
-	int acpi_idle_state = 0;
+	int acpi_idle_state = 0, pm, irq;
+	unsigned long ioaddr;
 
 	static int did_version = 0;			/* Already printed version info. */
+
+#ifdef USE_IO
+	ioaddr = pci_resource_start (pdev, 0);
+#else
+	ioaddr = pci_resource_start (pdev, 1);
+#endif
+	irq = pdev->irq;
+	
+	if (!request_region (pci_resource_start (pdev, 1),
+			     pci_resource_len (pdev, 1),
+			     EEPRO100_MODULE_NAME)) {
+		printk (KERN_ERR PFX "cannot reserve I/O ports\n");
+		goto err_out_none;
+	}
+	if (!request_mem_region (pci_resource_start (pdev, 0),
+				 pci_resource_len (pdev, 0),
+				 EEPRO100_MODULE_NAME)) {
+		printk (KERN_ERR PFX "cannot reserve MMIO region\n");
+		goto err_out_free_pio_region;
+	}
+	
+#ifndef USE_IO
+	ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 0),
+					  pci_resource_len (pdev, 0));
+	if (!ioaddr) {
+		printk (KERN_ERR PFX "cannot remap MMIO region %lx @ %lx\n",
+			pci_resource_len (pdev, 0),
+			pci_resource_start (pdev, 0));
+		goto err_out_free_mmio_region;
+	}
+#endif
+
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
-	pdev = pci_find_slot(pci_bus, pci_devfn);
-
 	tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
 					     + sizeof(struct speedo_stats), &tx_ring_dma);
 	if (!tx_ring) {
-		printk(KERN_ERR "Could not allocate DMA memory.\n");
-		return NULL;
+		printk(KERN_ERR PFX "Could not allocate DMA memory.\n");
+		goto err_out_iounmap;
 	}
 
 	dev = init_etherdev(NULL, sizeof(struct speedo_private));
 	if (dev == NULL) {
-		pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
-					  + sizeof(struct speedo_stats),
-				    tx_ring, tx_ring_dma);
-		return NULL;
+		printk(KERN_ERR PFX "Could not allocate ethernet device.\n");
+		goto err_out_free_tx_ring;
+	}
+	if (dev->priv == NULL) {
+		printk(KERN_ERR PFX "Could not allocate ethernet device private info.\n");
+		goto err_out_free_netdev;
 	}
 
 	if (dev->mem_start > 0)
 		option = dev->mem_start;
+#if MODULE_SETUP_FIXED
 	else if (card_idx >= 0  &&  options[card_idx] >= 0)
 		option = options[card_idx];
+#endif
 	else
 		option = 0;
 
-#if defined(HAS_PCI_NETIF)
-	acpi_idle_state = acpi_set_pwr_state(pci_bus, pci_devfn, ACPI_D0);
-#endif
+	/* save power state b4 pci_enable_device overwrites it */
+	pm = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm) {
+		u16 pwr_command;
+		pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command);
+		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
+	}
+
+	pci_enable_device (pdev);
+	pci_set_master (pdev);
 
 	/* Read the station address EEPROM before doing the reset.
 	   Nominally his should even be done before accepting the device, but
@@ -716,7 +629,7 @@
 	if (eeprom[3] & 0x0100)
 		product = "OEM i82557/i82558 10/100 Ethernet";
 	else
-		product = pci_tbl[chip_idx].name;
+		product = "Intel PCI EtherExpress Pro100";
 
 	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
 
@@ -724,7 +637,7 @@
 		printk("%2.2X:", dev->dev_addr[i]);
 	printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
 
-#ifndef kernel_bloat
+#if 1
 	/* OK, this is pure kernel bloat.  I don't like it when other drivers
 	   waste non-pageable kernel space to emit similar messages, but I need
 	   them for bug reports. */
@@ -793,41 +706,31 @@
 #endif  /* kernel_bloat */
 
 	outl(PortReset, ioaddr + SCBPort);
-#if defined(HAS_PCI_NETIF)
-	/* Return the chip to its original power state. */
-	acpi_set_pwr_state(pci_bus, pci_devfn, acpi_idle_state);
-#endif
 
-	/* We do a request_region() only to register /proc/ioports info. */
-	request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
+	/* Return the chip to its original power state. */
+	pci_set_power_state (pdev, acpi_idle_state);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
 	sp = dev->priv;
-	if (dev->priv == NULL) {
-		void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
-		dev->priv = sp = mem;		/* Cache align here if kmalloc does not. */
-		sp->priv_addr = mem;
-	}
 	memset(sp, 0, sizeof(*sp));
-	sp->next_module = root_speedo_dev;
-	root_speedo_dev = dev;
 
-	sp->pci_bus = pci_bus;
-	sp->pci_devfn = pci_devfn;
 	sp->pdev = pdev;
-	sp->chip_id = chip_idx;
 	sp->acpi_pwr = acpi_idle_state;
 	sp->tx_ring = (struct TxFD *)tx_ring;
 	sp->tx_ring_dma = tx_ring_dma;
 	sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
 	
 	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+
+#if MODULE_SETUP_FIXED
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			sp->full_duplex = full_duplex[card_idx];
 	}
+#endif
+
 	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
@@ -847,9 +750,30 @@
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &speedo_ioctl;
 
-	return dev;
+	return 0;
+
+err_out_free_netdev:
+	unregister_netdevice (dev);
+	kfree (dev);
+err_out_free_tx_ring:
+	pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+				  + sizeof(struct speedo_stats),
+			    tx_ring, tx_ring_dma);
+err_out_iounmap:
+#ifndef USE_IO
+	iounmap ((void *)ioaddr);
+#endif
+err_out_free_mmio_region:
+	release_mem_region (pci_resource_start (pdev, 0),
+			    pci_resource_len (pdev, 0));
+err_out_free_pio_region:
+	release_region (pci_resource_start (pdev, 1),
+			pci_resource_len (pdev, 1));
+err_out_none:
+	return -ENODEV;
 }
-
+
+
 /* Serial EEPROM section.
    A "bit" grungy, but we work our way through bit-by-bit :->. */
 /*  EEPROM_Ctrl bits. */
@@ -925,13 +849,11 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-#if defined(HAS_PCI_NETIF)
-	acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-#endif
-
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
+	pci_set_power_state(sp->pdev, 0);
+
 	/* Set up the Tx queue early.. */
 	sp->cur_tx = 0;
 	sp->dirty_tx = 0;
@@ -940,9 +862,9 @@
 	spin_lock_init(&sp->lock);
 
 	/* .. we can safely take handler calls during init. */
-	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
-		return -EAGAIN;
-	}
+	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev))
+		return -EBUSY;
+
 	MOD_INC_USE_COUNT;
 
 	dev->if_port = sp->default_port;
@@ -1059,6 +981,8 @@
 	     + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD),
 		 ioaddr + SCBPointer);
 	outw(CUStart, ioaddr + SCBCmd);
+	
+	netif_start_queue (dev);
 }
 
 /* Media monitoring and control. */
@@ -1220,6 +1144,7 @@
 	}
 	sp->stats.tx_errors++;
 	dev->trans_start = jiffies;
+	netif_start_queue (dev);
 	return;
 }
 
@@ -1230,6 +1155,8 @@
 	long ioaddr = dev->base_addr;
 	int entry;
 
+	netif_stop_queue (dev);
+
 	/* Caution: the write order is important here, set the base address
 	   with the "ownership" bits last. */
 
@@ -1270,13 +1197,15 @@
 		}
 		if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) {
 			sp->tx_full = 1;
-			netif_stop_queue(dev);
 		}
 		spin_unlock_irqrestore(&sp->lock, flags);
 	}
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outw(CUResume, ioaddr + SCBCmd);
 	dev->trans_start = jiffies;
+	
+	if (! sp->tx_full)
+		netif_start_queue (dev);
 
 	return 0;
 }
@@ -1300,6 +1229,8 @@
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 
+	spin_lock (&sp->lock);
+
 	do {
 		status = inw(ioaddr + SCBStatus);
 		/* Acknowledge all of the current interrupt sources ASAP. */
@@ -1330,7 +1261,6 @@
 		/* User interrupt, Command/Tx unit interrupt or CU not active. */
 		if (status & 0xA400) {
 			unsigned int dirty_tx;
-			spin_lock(&sp->lock);
 
 			dirty_tx = sp->dirty_tx;
 			while (sp->cur_tx - dirty_tx > 0) {
@@ -1380,10 +1310,12 @@
 				&&  sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) {
 				/* The ring is no longer full, clear tbusy. */
 				sp->tx_full = 0;
-				spin_unlock(&sp->lock);
-				netif_wake_queue(dev);
-			} else
-				spin_unlock(&sp->lock);
+			}
+			
+			if (sp->tx_full)
+				netif_stop_queue (dev);
+			else
+				netif_wake_queue (dev);
 		}
 
 		if (--boguscnt < 0) {
@@ -1399,7 +1331,7 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
-	return;
+	spin_unlock (&sp->lock);
 }
 
 static int
@@ -1546,7 +1478,7 @@
 #if LINUX_VERSION_CODE < 0x20100
 			skb->free = 1;
 #endif
-			dev_free_skb(skb);
+			dev_kfree_skb(skb);
 		}
 	}
 
@@ -1559,7 +1491,7 @@
 			pci_unmap_single(sp->pdev,
 							 le32_to_cpu(sp->tx_ring[i].tx_buf_addr0),
 							 skb->len);
-			dev_free_skb(skb);
+			dev_kfree_skb(skb);
 		}
 	}
 	if (sp->mc_setup_frm) {
@@ -1571,10 +1503,9 @@
 	if (speedo_debug > 3)
 		speedo_show_state(dev);
 
-#if defined(HAS_PCI_NETIF)
 	/* Alt: acpi_set_pwr_state(pci_bus, pci_devfn, sp->acpi_pwr); */
-	acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D2);
-#endif
+	pci_set_power_state (sp->pdev, 2);
+
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1626,32 +1557,22 @@
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
-#if defined(HAS_PCI_NETIF)
 	int saved_acpi;
-#endif
 
     switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-#if defined(HAS_PCI_NETIF)
-		saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-		data[3] = mdio_read(ioaddr, data[0], data[1]);
-		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
-		data[3] = mdio_read(ioaddr, data[0], data[1]);
-#endif
+		saved_acpi = pci_set_power_state (sp->pdev, 0);
+		data[3] = mdio_read (ioaddr, data[0], data[1]);
+		pci_set_power_state (sp->pdev, saved_acpi);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-#if defined(HAS_PCI_NETIF)
-		saved_acpi = acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, ACPI_D0);
-		mdio_write(ioaddr, data[0], data[1], data[2]);
-		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, saved_acpi);
-#else
+		saved_acpi = pci_set_power_state(sp->pdev, 0);
 		mdio_write(ioaddr, data[0], data[1], data[2]);
-#endif
+		pci_set_power_state(sp->pdev, saved_acpi);
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -1836,54 +1757,94 @@
 }
 
 
+static void eepro100_suspend (struct pci_dev *pdev)
+{
+	struct net_device *dev = pdev->driver_data;
+	long ioaddr = dev->base_addr;
+
+	netif_stop_queue (dev);
+	outl(PortPartialReset, ioaddr + SCBPort);
+}
+
+
+static void eepro100_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pdev->driver_data;
+	struct speedo_private *np = (struct speedo_private *)dev->priv;
+
+	speedo_resume(dev);
+	np->rx_mode = -1;
+	np->flow_ctrl = np->partner = 0;
+	set_rx_mode(dev);
+}
+
+
+static void __devexit eepro100_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pdev->driver_data;
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	
+	unregister_netdev (dev);
+
+	release_region (pci_resource_start (pdev, 1),
+			pci_resource_len (pdev, 1));
+	release_mem_region (pci_resource_start (pdev, 0),
+			    pci_resource_len (pdev, 0));
+
+#ifndef USE_IO
+	iounmap ((char *) dev->base_addr);
+#endif
+
+	pci_set_power_state (pdev, sp->acpi_pwr);
+
+	kfree (dev);
+}
+
+
+static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0,},
+};
+MODULE_DEVICE_TABLE (pci, eepro100_pci_tbl);
+
+	
+static struct pci_driver eepro100_driver = {
+	name:		EEPRO100_MODULE_NAME,
+	id_table:	eepro100_pci_tbl,
+	probe:		eepro100_init_one,
+	remove:		eepro100_remove_one,
+	suspend:	eepro100_suspend,
+	resume:		eepro100_resume,
+};
+
+
 static int __init eepro100_init_module(void)
 {
 	int cards_found;
 
 	if (debug >= 0)
 		speedo_debug = debug;
+
 	/* Always emit the version message. */
 	if (speedo_debug)
 		printk(KERN_INFO "%s", version);
 
-#if defined(HAS_PCI_NETIF)
-	cards_found = netif_pci_probe(pci_tbl);
-	if (cards_found < 0)
-		printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
-	return cards_found;
-#else
-	cards_found = eepro100_init();
+	cards_found = pci_register_driver (&eepro100_driver);
 	if (cards_found <= 0) {
-		printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
+		printk(KERN_INFO PFX "No cards found, driver not installed.\n");
 		return -ENODEV;
 	}
-#endif
+
 	return 0;
 }
 
+
 static void __exit eepro100_cleanup_module(void)
 {
-	struct net_device *next_dev;
-
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_speedo_dev) {
-		struct speedo_private *sp = (void *)root_speedo_dev->priv;
-		unregister_netdev(root_speedo_dev);
-#ifdef USE_IO
-		release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
-#else
-		iounmap((char *)root_speedo_dev->base_addr);
-#endif
-#if defined(HAS_PCI_NETIF)
-		acpi_set_pwr_state(sp->pci_bus, sp->pci_devfn, sp->acpi_pwr);
-#endif
-		next_dev = sp->next_module;
-		if (sp->priv_addr)
-			kfree(sp->priv_addr);
-		kfree(root_speedo_dev);
-		root_speedo_dev = next_dev;
-	}
+	pci_unregister_driver (&eepro100_driver);
 }
+
 
 module_init(eepro100_init_module);
 module_exit(eepro100_cleanup_module);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.3.44/linux/drivers/net/epic100.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/epic100.c	Sun Feb 13 18:24:12 2000
@@ -79,7 +79,6 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
 
 /* The I/O extent. */
 #define EPIC_TOTAL_SIZE 0x100
@@ -425,6 +424,8 @@
 	dev->do_ioctl = &mii_ioctl;
 	dev->tx_timeout = epic_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	
+	netif_stop_queue (dev);
 
 	return dev;
 }
@@ -527,13 +528,15 @@
 	int mii_reg5;
 	ep->full_duplex = ep->force_fd;
 
+	MOD_INC_USE_COUNT;
+
 	/* Soft reset the chip. */
 	outl(0x4001, ioaddr + GENCTL);
 
-	if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev))
-		return -EAGAIN;
-
-	MOD_INC_USE_COUNT;
+	if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev)) {
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
 
 	epic_init_ring(dev);
 
@@ -581,8 +584,6 @@
 	set_rx_mode(dev);
 	outl(0x000A, ioaddr + COMMAND);
 
-	netif_start_queue(dev);
-
 	/* Enable interrupts by setting the interrupt mask. */
 	outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
 		 | CntFull | TxUnderrun | TxDone
@@ -595,10 +596,12 @@
 			   dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
 			   ep->full_duplex ? "full" : "half");
 
+	netif_start_queue(dev);
+
 	/* Set the timer to switch to check for link beat and perhaps switch
 	   to an alternate media type. */
 	init_timer(&ep->timer);
-	ep->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	ep->timer.expires = RUN_AT(3*HZ);			/* 3 sec. */
 	ep->timer.data = (unsigned long)dev;
 	ep->timer.function = &epic_timer;				/* timer handler */
 	add_timer(&ep->timer);
@@ -613,6 +616,8 @@
 	long ioaddr = dev->base_addr;
 	struct epic_private *ep = (struct epic_private *)dev->priv;
 
+	netif_stop_queue (dev);
+	
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x00000000, ioaddr + INTMASK);
 	/* Stop the chip's Tx and Rx DMA processes. */
@@ -671,11 +676,13 @@
 		 | CntFull | TxUnderrun | TxDone
 		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
 		 ioaddr + INTMASK);
+
+	netif_start_queue (dev);
+	
 	printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
 		   " interrupt %4.4x.\n",
 			   dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL),
 		   inl(ioaddr + INTSTAT));
-	return;
 }
 
 static void epic_timer(unsigned long data)
@@ -738,7 +745,8 @@
 
 	dev->trans_start = jiffies;
 	ep->stats.tx_errors++;
-	return;
+	
+	netif_start_queue (dev);
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -790,6 +798,8 @@
 	int entry;
 	u32 flag;
 
+	netif_stop_queue (dev);
+
 	/* Caution: the write order is important here, set the base address
 	   with the "ownership" bits last. */
 
@@ -806,13 +816,10 @@
 	
 	if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
 	  flag = 0x10; /* No interrupt */
-	  netif_start_queue(dev);
 	} else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) {
 	  flag = 0x14; /* Tx-done intr. */
-	  netif_start_queue(dev);
 	} else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) {
 	  flag = 0x10; /* No Tx-done intr. */
-	  netif_start_queue(dev);
 	} else {
 	  /* Leave room for two additional entries. */
 	  flag = 0x14; /* Tx-done intr. */
@@ -826,6 +833,10 @@
 	outl(0x0004, dev->base_addr + COMMAND);
 
 	dev->trans_start = jiffies;
+
+	if (! ep->tx_full)
+		netif_start_queue (dev);
+
 	if (epic_debug > 4)
 		printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
 			   "flag %2.2x Tx status %8.8x.\n",
@@ -895,7 +906,7 @@
 				}
 
 				/* Free the original skb. */
-				DEV_FREE_SKB(ep->tx_skbuff[entry]);
+				dev_kfree_skb_irq(ep->tx_skbuff[entry]);
 				ep->tx_skbuff[entry] = 0;
 			}
 
@@ -912,8 +923,12 @@
 			    dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				ep->tx_full = 0;
-				netif_wake_queue (dev);
 			}
+			
+			if (ep->tx_full)
+				netif_stop_queue (dev);
+			else
+				netif_wake_queue (dev);
 
 			ep->dirty_tx = dirty_tx;
 		}
@@ -1073,12 +1088,12 @@
 		ep->rx_ring[i].buflength = 0;
 		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
 		if (skb) {
-			DEV_FREE_SKB(skb);
+			dev_kfree_skb(skb);
 		}
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (ep->tx_skbuff[i])
-			DEV_FREE_SKB(ep->tx_skbuff[i]);
+			dev_kfree_skb(ep->tx_skbuff[i]);
 		ep->tx_skbuff[i] = 0;
 	}
 
@@ -1224,13 +1239,14 @@
 	struct net_device *dev;
 	u16 dev_id;
 	u32 io;
-	u8 bus, devfn, irq;
+	u8 irq;
 	struct pci_dev *pdev;
 
 	if (loc->bus != LOC_PCI) return NULL;
 	pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
 	if (!pdev) return NULL;
-	printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn);
+	printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n",
+	       pdev->bus->number, pdev->devfn);
 	io = pdev->resource[0].start;
 	irq = pdev->irq;
 	dev_id = pdev->device;
@@ -1241,7 +1257,7 @@
 			   io == 0 ? "I/O address" : "IRQ");
 		return NULL;
 	}
-	dev = epic_probe1(bus, devfn, io, irq, 2, -1);
+	dev = epic_probe1(pdev, io, irq, 2, -1);
 	if (dev) {
 		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
 		strcpy(node->dev_name, dev->name);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.3.44/linux/drivers/net/eth16i.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/net/eth16i.c	Sun Feb 13 18:20:21 2000
@@ -158,6 +158,8 @@
 #include <linux/malloc.h>		  
 #include <linux/string.h>		  
 #include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -168,26 +170,7 @@
 #include <asm/io.h>		  
 #include <asm/dma.h>
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#endif
 
-#if LINUX_VERSION_CODE < 0x20138
-#define test_and_set_bit(val,addr) set_bit(val,addr)
-#endif
-
-#if LINUX_VERSION_CODE < 0x020100
-typedef struct enet_statistics eth16i_stats_type;
-#else
-typedef struct net_device_stats eth16i_stats_type;
-#endif
 
 /* Few macros */
 #define BIT(a)		       ( (1 << (a)) )  
@@ -371,12 +354,14 @@
 #define RESET                  ID_ROM_0
 
 /* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] =
-   { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
+static unsigned int eth16i_portlist[] = {
+	0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 
+};
 
-static unsigned int eth32i_portlist[] =
-   { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
-     0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
+static unsigned int eth32i_portlist[] = { 
+	0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+	0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 
+};
 
 /* This is the Interrupt lookup table for Eth16i card */
 static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
@@ -399,7 +384,7 @@
 /* Information for each board */
 
 struct eth16i_local {
-	eth16i_stats_type stats;
+	struct net_device_stats stats;
 	unsigned char     tx_started;
 	unsigned char     tx_buf_busy;
 	unsigned short    tx_queue;  /* Number of packets in transmit buffer */
@@ -409,6 +394,7 @@
 	unsigned long     tx_buffered_packets;
 	unsigned long     tx_buffered_bytes;
 	unsigned long     col_16;
+	spinlock_t	  lock;
 };
 
 /* Function prototypes */
@@ -429,8 +415,10 @@
 static int     eth16i_close(struct net_device *dev);
 static int     eth16i_tx(struct sk_buff *skb, struct net_device *dev);
 static void    eth16i_rx(struct net_device *dev);
+static void    eth16i_timeout(struct net_device *dev);
 static void    eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void    eth16i_reset(struct net_device *dev);
+static void    eth16i_timeout(struct net_device *dev);
 static void    eth16i_skip_packet(struct net_device *dev);
 static void    eth16i_multicast(struct net_device *dev); 
 static void    eth16i_select_regbank(unsigned char regbank, int ioaddr);
@@ -444,18 +432,10 @@
 static ushort  eth16i_parse_mediatype(const char* s);
 #endif
 
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev);
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
 
 static char *cardname = "ICL EtherTeam 16i/32";
 
-#ifdef HAVE_DEVLIST 
-
-/* Support for alternate probe manager */
-/struct netdev_entry eth16i_drv = 
- {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list}; 
-
-#else  /* Not HAVE_DEVLIST */
-
 int __init eth16i_probe(struct net_device *dev)
 {
 	int i;
@@ -488,10 +468,11 @@
 
 	return ENODEV;
 }
-#endif  /* Not HAVE_DEVLIST */
 
 static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
 {
+	struct eth16i_local *lp;
+	
 	static unsigned version_printed = 0;
 	boot = 1;  /* To inform initilization that we are in boot probe */
 
@@ -535,17 +516,6 @@
 		printk(KERN_INFO "%s", version);
 
 	dev->base_addr = ioaddr;
-	
-#if 0
-	if(dev->irq) {
-		if(eth16i_set_irq(dev)) {
-			dev->irq = eth16i_get_irq(ioaddr);
-		}
-
-	}
-	else {
-#endif
-
 	dev->irq = eth16i_get_irq(ioaddr);
 
 	/* Try to obtain interrupt vector */
@@ -556,10 +526,6 @@
 		return -EAGAIN;
 	}
 
-#if 0
-	irq2dev_map[dev->irq] = dev;
-#endif
-
 	printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
 	       dev->name, cardname, ioaddr, dev->irq);
 
@@ -583,12 +549,16 @@
 	}
 
 	memset(dev->priv, 0, sizeof(struct eth16i_local));
-
 	dev->open               = eth16i_open;
 	dev->stop               = eth16i_close;
 	dev->hard_start_xmit    = eth16i_tx;
 	dev->get_stats          = eth16i_get_stats;
-	dev->set_multicast_list = &eth16i_multicast;
+	dev->set_multicast_list = eth16i_multicast;
+	dev->tx_timeout 	= eth16i_timeout;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+
+	lp = (struct eth16i_local *)dev->priv;
+	spin_lock_init(&lp->lock);
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
@@ -1004,10 +974,7 @@
 	/* Turn on interrupts*/
 	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);  
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
+	netif_start_queue(dev);
 	MOD_INC_USE_COUNT;
 
 	return 0;
@@ -1023,9 +990,8 @@
 	/* Turn off interrupts*/
 	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);  
 
-	dev->start = 0;
-	dev->tbusy = 1;
-
+	netif_stop_queue(dev);
+	
 	lp->open_time = 0;
 
 	/* Disable transmit and receive */
@@ -1042,153 +1008,115 @@
 	return 0;
 }
 
-static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+static void eth16i_timeout(struct net_device *dev)
 {
 	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	int status = 0;
+	/* 
+	   If we get here, some higher level has decided that 
+	   we are broken. There should really be a "kick me" 
+	   function call instead. 
+	   */
 
-	if(dev->tbusy) {
-		
-		/* 
-		   If we get here, some higher level has decided that 
-		   we are broken. There should really be a "kick me" 
-		   function call instead. 
-		   */
-
-		int tickssofar = jiffies - dev->trans_start;
-		if(tickssofar < TX_TIMEOUT)  
-			return 1;                     
-
-		outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
-		printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", 
-		       dev->name,
-		       inw(ioaddr + TX_STATUS_REG), 
-		       (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? 
+	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+	printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", 
+	       dev->name,
+	inw(ioaddr + TX_STATUS_REG),  (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? 
 		       "IRQ conflict" : "network cable problem");
 
-		dev->trans_start = jiffies;
-
-		/* Let's dump all registers */
-		if(eth16i_debug > 0) { 
-			printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
-			       dev->name, inb(ioaddr + 0), 
-			       inb(ioaddr + 1), inb(ioaddr + 2), 
-			       inb(ioaddr + 3), inb(ioaddr + 4), 
-			       inb(ioaddr + 5),
-			       inb(ioaddr + 6), inb(ioaddr + 7));
-
-			printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
-			       dev->name, inb(ioaddr + TRANSMIT_START_REG),
-			       inb(ioaddr + COL_16_REG));
+	dev->trans_start = jiffies;
 
+	/* Let's dump all registers */
+	if(eth16i_debug > 0) { 
+		printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+		       dev->name, inb(ioaddr + 0), 
+		       inb(ioaddr + 1), inb(ioaddr + 2), 
+		       inb(ioaddr + 3), inb(ioaddr + 4), 
+		       inb(ioaddr + 5),
+		       inb(ioaddr + 6), inb(ioaddr + 7));
+
+		printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+		       dev->name, inb(ioaddr + TRANSMIT_START_REG),
+		       inb(ioaddr + COL_16_REG));
 			printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
-			printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
-			printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
-
-		}
-
-		lp->stats.tx_errors++;
-
-		eth16i_reset(dev);
-
-		dev->trans_start = jiffies;
-
-		outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+		printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+		printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
 	}
+	lp->stats.tx_errors++;
+	eth16i_reset(dev);
+	dev->trans_start = jiffies;
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	netif_wake_queue(dev);
+}
 
-	/* 
-	   If some higher layer thinks we've missed an tx-done interrupt
-	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-	   itself 
-	   */
-	
-	if(skb == NULL) {
-#if LINUX_VERSION_CODE < 0x020100
-		dev_tint(dev);
-#endif
-		if(eth16i_debug > 0) 
-			printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);
-		return 0;
-	}
+static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int status = 0;
+	ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char *buf = skb->data;
+	unsigned long flags;
 
-	/* Block a timer based transmitter from overlapping. 
-	   This could better be done with atomic_swap(1, dev->tbusy), 
-	   but set_bit() works as well. */
 
-	set_bit(0, (void *)&lp->tx_buf_busy);
-	
+	netif_stop_queue(dev);
+		
 	/* Turn off TX interrupts */
 	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+	
+	/* We would be better doing the disable_irq tricks the 3c509 does,
+	   that would make this suck a lot less */
+	   
+	spin_lock_irqsave(&lp->lock, flags);
 
-	if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-		status = -1;
-	}
+	if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+		if(eth16i_debug > 0) 
+			printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);  
+	} 
 	else {
-		ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
+		outw(length, ioaddr + DATAPORT);
 
-		if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
-			if(eth16i_debug > 0) 
-				printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);  
-		} 
+		if( ioaddr < 0x1000 ) 
+			outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
 		else {
-			outw(length, ioaddr + DATAPORT);
-
-			if( ioaddr < 0x1000 ) 
-				outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-			else {
-				unsigned char frag = length % 4;
-
-				outsl(ioaddr + DATAPORT, buf, length >> 2);
-
-				if( frag != 0 ) {
-					outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
-					if( frag == 3 ) 
-						outsw(ioaddr + DATAPORT, 
-						      (buf + (length & 0xFFFC) + 2), 1);
-				}
+			unsigned char frag = length % 4;
+			outsl(ioaddr + DATAPORT, buf, length >> 2);
+			if( frag != 0 ) {
+				outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+				if( frag == 3 ) 
+					outsw(ioaddr + DATAPORT, 
+					      (buf + (length & 0xFFFC) + 2), 1);
 			}
-
-			lp->tx_buffered_packets++;
-			lp->tx_buffered_bytes = length;
-			lp->tx_queue++;
-			lp->tx_queue_len += length + 2;
 		}
-		
-		lp->tx_buf_busy = 0;
+		lp->tx_buffered_packets++;
+		lp->tx_buffered_bytes = length;
+		lp->tx_queue++;
+		lp->tx_queue_len += length + 2;
+	}
+	lp->tx_buf_busy = 0;
 
-		if(lp->tx_started == 0) {
-			/* If the transmitter is idle..always trigger a transmit */
-			outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
-			lp->tx_queue = 0;
-			lp->tx_queue_len = 0;
-			dev->trans_start = jiffies;
-			lp->tx_started = 1;
-			dev->tbusy = 0;
-		}
-		else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
-			/* There is still more room for one more packet in tx buffer */
-			dev->tbusy = 0;
-		}
-		
-		outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	if(lp->tx_started == 0) {
+		/* If the transmitter is idle..always trigger a transmit */
+		outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+		lp->tx_queue = 0;
+		lp->tx_queue_len = 0;
+		dev->trans_start = jiffies;
+		lp->tx_started = 1;
+		netif_wake_queue(dev);
+	}
+	else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+		/* There is still more room for one more packet in tx buffer */
+		netif_wake_queue(dev);
+	}
 		
-		/* Turn TX interrupts back on */
-		/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
-		status = 0;
-	} 
-
-#if LINUX_VERSION_CODE >= 0x020100
+	spin_unlock_irqrestore(&lp->lock, flags);
+	
+	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+	/* Turn TX interrupts back on */
+	/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
+	status = 0;
 	dev_kfree_skb(skb);
-#else
-	dev_kfree_skb(skb, FREE_WRITE);
-#endif
-
-	return status;
+	return 0;
 }
 
 static void eth16i_rx(struct net_device *dev)
@@ -1284,51 +1212,23 @@
 			break;
 
 	} /* while */
-
-#if 0
-	{
-		int i;
-
-		for(i = 0; i < 20; i++) {
-			if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 
-			    RX_BUFFER_EMPTY)
-				break;
-			inw(ioaddr + DATAPORT);
-			outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
-		}
-
-		if(eth16i_debug > 1)
-			printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);
-	}
-#endif
-
-	return;
 }
 
 static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	struct eth16i_local *lp;
-	int ioaddr = 0,
-		status;
+	int ioaddr = 0, status;
 
-	if(dev == NULL) {
-		printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);
-		return;
-	}
+	ioaddr = dev->base_addr;
+	lp = (struct eth16i_local *)dev->priv;
 
 	/* Turn off all interrupts from adapter */
 	outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
 
-	set_bit(0, (void *)&dev->tbusy);  	/* Set the device busy so that */
 	/* eth16i_tx wont be called */
+	spin_lock(&lp->lock);
 
-	if(dev->interrupt)
-		printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
-	dev->interrupt = 1;
-
-	ioaddr = dev->base_addr;
-	lp = (struct eth16i_local *)dev->priv;
 	status = inw(ioaddr + TX_STATUS_REG);      /* Get the status */
 	outw(status, ioaddr + TX_STATUS_REG);      /* Clear status bits */
 
@@ -1386,13 +1286,11 @@
 				lp->tx_queue = 0;
 				lp->tx_queue_len = 0;
 				lp->tx_started = 1;
-				dev->trans_start = jiffies;
-				mark_bh(NET_BH); 
 			}
 			else {
 				lp->tx_started = 0;
-				mark_bh(NET_BH);
 			}
+			netif_wake_queue(dev);
 		}
 	}
 
@@ -1401,16 +1299,16 @@
 		eth16i_rx(dev);  /* We have packet in receive buffer */
 	}  
 	
-	dev->interrupt = 0;
-	
 	/* Turn interrupts back on */
 	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
 	
 	if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
 		/* There is still more room for one more packet in tx buffer */
-		dev->tbusy = 0;
+		netif_wake_queue(dev);
 	}
 	
+	spin_unlock(&lp->lock);
+	
 	return;
 }
 
@@ -1442,10 +1340,6 @@
 	lp->tx_buf_busy = 0;
 	lp->tx_queue = 0;
 	lp->tx_queue_len = 0;    
-
-	dev->interrupt = 0;
-	dev->start = 1;
-	dev->tbusy = 0;
 	BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
 }
 
@@ -1462,10 +1356,9 @@
 	}
 }
 
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev)
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
 {
 	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-
 	return &lp->stats;
 }
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.3.44/linux/drivers/net/ewrk3.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/ewrk3.c	Sun Feb 13 18:20:21 2000
@@ -303,6 +303,7 @@
 static void ewrk3_init(struct net_device *dev);
 static int ewrk3_rx(struct net_device *dev);
 static int ewrk3_tx(struct net_device *dev);
+static void ewrk3_timeout(struct net_device *dev);
 
 static void EthwrkSignature(char *name, char *eeprom_image);
 static int DevicePresent(u_long iobase);
@@ -601,12 +602,14 @@
 				printk(version);
 			}
 			/* The EWRK3-specific entries in the device structure. */
-			dev->open = &ewrk3_open;
-			dev->hard_start_xmit = &ewrk3_queue_pkt;
-			dev->stop = &ewrk3_close;
-			dev->get_stats = &ewrk3_get_stats;
-			dev->set_multicast_list = &set_multicast_list;
-			dev->do_ioctl = &ewrk3_ioctl;
+			dev->open = ewrk3_open;
+			dev->hard_start_xmit = ewrk3_queue_pkt;
+			dev->stop = ewrk3_close;
+			dev->get_stats = ewrk3_get_stats;
+			dev->set_multicast_list = set_multicast_list;
+			dev->do_ioctl = ewrk3_ioctl;
+			dev->tx_timeout = ewrk3_timeout;
+			dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
 
 			dev->mem_start = 0;
 
@@ -616,7 +619,6 @@
 	} else {
 		status = -ENXIO;
 	}
-
 	return status;
 }
 
@@ -664,10 +666,7 @@
 				printk("  cmr:  0x%02x\n", inb(EWRK3_CMR));
 				printk("  fmqc: 0x%02x\n", inb(EWRK3_FMQC));
 			}
-			dev->tbusy = 0;
-			dev->start = 1;
-			dev->interrupt = UNMASK_INTERRUPTS;
-
+			netif_start_queue(dev);
 			/*
 			   ** Unmask EWRK3 board interrupts
 			 */
@@ -676,10 +675,9 @@
 
 		}
 	} else {
-		dev->start = 0;
-		dev->tbusy = 1;
-		printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);
-		printk("      Run the 'ewrk3setup' utility or remove the hard straps.\n");
+		printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name);
+		printk(KERN_ERR "      Run the 'ewrk3setup' utility or remove the hard straps.\n");
+		return -EINVAL;
 	}
 
 	MOD_INC_USE_COUNT;
@@ -722,149 +720,148 @@
 }
 
 /*
-   ** Writes a socket buffer to the free page queue
+ *  Transmit timeout
  */
-static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+ 
+static void ewrk3_timeout(struct net_device *dev)
 {
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
-	u_long iobase = dev->base_addr;
-	int status = 0;
 	u_char icr, csr;
+	u_long iobase = dev->base_addr;
+	
+	if (!lp->hard_strapped) 
+	{
+		printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
+		       dev->name, inb(EWRK3_CSR));
 
-	/* Transmitter timeout, serious problems. */
-	if (dev->tbusy || lp->lock) {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < QUEUE_PKT_TIMEOUT) {
-			status = -1;
-		} else if (!lp->hard_strapped) {
-			printk("%s: transmit timed/locked out, status %04x, resetting.\n",
-			       dev->name, inb(EWRK3_CSR));
-
-			/*
-			   ** Mask all board interrupts
-			 */
-			DISABLE_IRQs;
-
-			/*
-			   ** Stop the TX and RX...
-			 */
-			STOP_EWRK3;
-
-			ewrk3_init(dev);
-
-			/*
-			   ** Unmask EWRK3 board interrupts
-			 */
-			ENABLE_IRQs;
-
-			dev->tbusy = 0;
-			dev->trans_start = jiffies;
-		}
-	} else if (skb->len > 0) {
+		/*
+		   ** Mask all board interrupts
+		 */
+		DISABLE_IRQs;
 
 		/*
-		   ** Block a timer-based transmit from overlapping.  This could better be
-		   ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+		   ** Stop the TX and RX...
 		 */
-		if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
-			printk("%s: Transmitter access conflict.\n", dev->name);
+		STOP_EWRK3;
 
-		DISABLE_IRQs;	/* So that the page # remains correct */
+		ewrk3_init(dev);
 
 		/*
-		   ** Get a free page from the FMQ when resources are available
+		   ** Unmask EWRK3 board interrupts
 		 */
-		if (inb(EWRK3_FMQC) > 0) {
-			u_long buf = 0;
-			u_char page;
+		ENABLE_IRQs;
 
-			if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
-				/*
-				   ** Set up shared memory window and pointer into the window
-				 */
-				while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */
-				if (lp->shmem_length == IO_ONLY) {
-					outb(page, EWRK3_IOPR);
-				} else if (lp->shmem_length == SHMEM_2K) {
-					buf = lp->shmem_base;
-					outb(page, EWRK3_MPR);
-				} else if (lp->shmem_length == SHMEM_32K) {
-					buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
-					outb((page >> 4), EWRK3_MPR);
-				} else if (lp->shmem_length == SHMEM_64K) {
-					buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
-					outb((page >> 5), EWRK3_MPR);
-				} else {
-					status = -1;
-					printk("%s: Oops - your private data area is hosed!\n", dev->name);
-				}
+		dev->trans_start = jiffies;
+		netif_wake_queue(dev);
+	}
+}
 
-				if (!status) {
+/*
+   ** Writes a socket buffer to the free page queue
+ */
+static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	u_long iobase = dev->base_addr;
+	int status = 0;
+	u_char icr;
 
-					/*
-					   ** Set up the buffer control structures and copy the data from
-					   ** the socket buffer to the shared memory .
-					 */
+	netif_stop_queue(dev);
+#ifdef CONFIG_SMP
+#error "This needs spinlocks"
+#endif
+	DISABLE_IRQs;	/* So that the page # remains correct */
 
-					if (lp->shmem_length == IO_ONLY) {
-						int i;
-						u_char *p = skb->data;
+	/*
+	   ** Get a free page from the FMQ when resources are available
+	 */
+	if (inb(EWRK3_FMQC) > 0) 
+	{
+		u_long buf = 0;
+		u_char page;
 
+		if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
+			/*
+			   ** Set up shared memory window and pointer into the window
+			 */
+			while (test_and_set_bit(0, (void *) &lp->lock) != 0);	/* Wait for lock to free */
+			if (lp->shmem_length == IO_ONLY) {
+				outb(page, EWRK3_IOPR);
+			} else if (lp->shmem_length == SHMEM_2K) {
+				buf = lp->shmem_base;
+				outb(page, EWRK3_MPR);
+			} else if (lp->shmem_length == SHMEM_32K) {
+				buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
+				outb((page >> 4), EWRK3_MPR);
+			} else if (lp->shmem_length == SHMEM_64K) {
+				buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
+				outb((page >> 5), EWRK3_MPR);
+			} else {
+				status = -1;
+				printk(KERN_ERR "%s: Oops - your private data area is hosed!\n", dev->name);
+			}
+
+			if (!status) {
+				/*
+				   ** Set up the buffer control structures and copy the data from
+				   ** the socket buffer to the shared memory .
+				 */
+					if (lp->shmem_length == IO_ONLY) {
+					int i;
+					u_char *p = skb->data;
 						outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
-						outb((char) (skb->len & 0xff), EWRK3_DATA);
-						outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
-						outb((char) 0x04, EWRK3_DATA);
-						for (i = 0; i < skb->len; i++) {
-							outb(*p++, EWRK3_DATA);
-						}
+					outb((char) (skb->len & 0xff), EWRK3_DATA);
+					outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
+					outb((char) 0x04, EWRK3_DATA);
+					for (i = 0; i < skb->len; i++) {
+						outb(*p++, EWRK3_DATA);
+					}
+					outb(page, EWRK3_TQ);	/* Start sending pkt */
+				} else {
+					writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf);	/* ctrl byte */
+					buf += 1;
+					writeb((char) (skb->len & 0xff), (char *) buf);		/* length (16 bit xfer) */
+					buf += 1;
+					if (lp->txc) {
+						writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
+						buf += 1;
+						writeb(0x04, (char *) buf);	/* index byte */
+						buf += 1;
+						writeb(0x00, (char *) (buf + skb->len));	/* Write the XCT flag */
+						isa_memcpy_toio(buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
 						outb(page, EWRK3_TQ);	/* Start sending pkt */
+						isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
+						writeb(0xff, (char *) (buf + skb->len));	/* Write the XCT flag */
 					} else {
-						writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf);	/* ctrl byte */
+						writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
 						buf += 1;
-						writeb((char) (skb->len & 0xff), (char *) buf);		/* length (16 bit xfer) */
+						writeb(0x04, (char *) buf);	/* index byte */
 						buf += 1;
-						if (lp->txc) {
-							writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
-							buf += 1;
-							writeb(0x04, (char *) buf);	/* index byte */
-							buf += 1;
-							writeb(0x00, (char *) (buf + skb->len));	/* Write the XCT flag */
-							isa_memcpy_toio(buf, skb->data, PRELOAD);	/* Write PRELOAD bytes */
-							outb(page, EWRK3_TQ);	/* Start sending pkt */
-							isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
-							writeb(0xff, (char *) (buf + skb->len));	/* Write the XCT flag */
-						} else {
-							writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
-							buf += 1;
-							writeb(0x04, (char *) buf);	/* index byte */
-							buf += 1;
-							isa_memcpy_toio(buf, skb->data, skb->len);		/* Write data bytes */
-							outb(page, EWRK3_TQ);	/* Start sending pkt */
-						}
+						isa_memcpy_toio(buf, skb->data, skb->len);		/* Write data bytes */
+						outb(page, EWRK3_TQ);	/* Start sending pkt */
 					}
-
-					dev->trans_start = jiffies;
-					dev_kfree_skb(skb);
-
-				} else {	/* return unused page to the free memory queue */
-					outb(page, EWRK3_FMQ);
 				}
-				lp->lock = 0;	/* unlock the page register */
-			} else {
-				printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
-				       (u_char) page);
+
+				dev->trans_start = jiffies;
+				dev_kfree_skb(skb);
+			} else {	/* return unused page to the free memory queue */
+				outb(page, EWRK3_FMQ);
 			}
+			lp->lock = 0;	/* unlock the page register */
 		} else {
-			printk("ewrk3_queue_pkt(): No free resources...\n");
-			printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+			printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
+			       (u_char) page);
 		}
+	} else {
+		printk(KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n", dev->name);
+		printk(KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", dev->name, inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+	}
 
-		/* Check for free resources: clear 'tbusy' if there are some */
-		if (inb(EWRK3_FMQC) > 0) {
-			dev->tbusy = 0;
-		}
-		ENABLE_IRQs;
+	/* Check for free resources: clear 'tbusy' if there are some */
+	if (inb(EWRK3_FMQC) > 0) {
+		netif_wake_queue(dev);
 	}
+	ENABLE_IRQs;
 	return status;
 }
 
@@ -878,60 +875,46 @@
 	u_long iobase;
 	u_char icr, cr, csr;
 
-	if (dev == NULL) {
-		printk("ewrk3_interrupt(): irq %d for unknown device.\n", irq);
-	} else {
-		lp = (struct ewrk3_private *) dev->priv;
-		iobase = dev->base_addr;
-
-		if (dev->interrupt)
-			printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
-		dev->interrupt = MASK_INTERRUPTS;
+	lp = (struct ewrk3_private *) dev->priv;
+	iobase = dev->base_addr;
 
-		/* get the interrupt information */
-		csr = inb(EWRK3_CSR);
-
-		/*
-		   ** Mask the EWRK3 board interrupts and turn on the LED
-		 */
-		DISABLE_IRQs;
-
-		cr = inb(EWRK3_CR);
-		cr |= CR_LED;
-		outb(cr, EWRK3_CR);
+	/* get the interrupt information */
+	csr = inb(EWRK3_CSR);
 
-		if (csr & CSR_RNE)	/* Rx interrupt (packet[s] arrived) */
-			ewrk3_rx(dev);
+	/*
+	 ** Mask the EWRK3 board interrupts and turn on the LED
+	 */
+	DISABLE_IRQs;
 
-		if (csr & CSR_TNE)	/* Tx interrupt (packet sent) */
-			ewrk3_tx(dev);
+	cr = inb(EWRK3_CR);
+	cr |= CR_LED;
+	outb(cr, EWRK3_CR);
 
-		/*
-		   ** Now deal with the TX/RX disable flags. These are set when there
-		   ** are no more resources. If resources free up then enable these
-		   ** interrupts, otherwise mask them - failure to do this will result
-		   ** in the system hanging in an interrupt loop.
-		 */
-		if (inb(EWRK3_FMQC)) {	/* any resources available? */
-			lp->irq_mask |= ICR_TXDM | ICR_RXDM;	/* enable the interrupt source */
-			csr &= ~(CSR_TXD | CSR_RXD);	/* ensure restart of a stalled TX or RX */
-			outb(csr, EWRK3_CSR);
-			dev->tbusy = 0;		/* clear TX busy flag */
-			mark_bh(NET_BH);
-		} else {
-			lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM);		/* disable the interrupt source */
-		}
+	if (csr & CSR_RNE)	/* Rx interrupt (packet[s] arrived) */
+		ewrk3_rx(dev);
 
-		/* Unmask the EWRK3 board interrupts and turn off the LED */
-		cr &= ~CR_LED;
-		outb(cr, EWRK3_CR);
+	if (csr & CSR_TNE)	/* Tx interrupt (packet sent) */
+		ewrk3_tx(dev);
 
-		dev->interrupt = UNMASK_INTERRUPTS;
-		ENABLE_IRQs;
+	/*
+	 ** Now deal with the TX/RX disable flags. These are set when there
+	 ** are no more resources. If resources free up then enable these
+	 ** interrupts, otherwise mask them - failure to do this will result
+	 ** in the system hanging in an interrupt loop.
+	 */
+	if (inb(EWRK3_FMQC)) {	/* any resources available? */
+		lp->irq_mask |= ICR_TXDM | ICR_RXDM;	/* enable the interrupt source */
+		csr &= ~(CSR_TXD | CSR_RXD);	/* ensure restart of a stalled TX or RX */
+		outb(csr, EWRK3_CSR);
+		netif_wake_queue(dev);
+	} else {
+		lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM);		/* disable the interrupt source */
 	}
 
-	return;
+	/* Unmask the EWRK3 board interrupts and turn off the LED */
+	cr &= ~CR_LED;
+	outb(cr, EWRK3_CR);
+	ENABLE_IRQs;
 }
 
 static int ewrk3_rx(struct net_device *dev)
@@ -1120,9 +1103,8 @@
 	u_long iobase = dev->base_addr;
 	u_char icr, csr;
 
-	dev->start = 0;
-	dev->tbusy = 1;
-
+	netif_stop_queue(dev);
+	
 	if (ewrk3_debug > 1) {
 		printk("%s: Shutting down ethercard, status was %2.2x.\n",
 		       dev->name, inb(EWRK3_CSR));
@@ -1369,8 +1351,7 @@
    ** are not available then insert a new device structure at the end of
    ** the current list.
  */
-static struct net_device * __init 
-alloc_device(struct net_device *dev, u_long iobase)
+static struct net_device * __init  alloc_device(struct net_device *dev, u_long iobase)
 {
 	struct net_device *adev = NULL;
 	int fixed = 0, new_dev = 0;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- v2.3.44/linux/drivers/net/fc/iph5526.c	Thu Nov 11 20:11:40 1999
+++ linux/drivers/net/fc/iph5526.c	Sun Feb 13 18:20:21 2000
@@ -919,7 +919,8 @@
 				/* An IP frame was transmitted to a Bad AL_PA. Free up
 			 	 * the skb used.
 			 	 */
-				dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id)));
+				dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
+				netif_wake_queue(fi->dev);
 			}
 		} /* End of IP frame timing out. */
 	} /* End of frame timing out. */
@@ -977,7 +978,8 @@
 			 * Free the skb that was used for this IP frame.
 			 */
 			if ((status == 0) && (seq_count > 1)) {
-				dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id)));
+				dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
+				netif_wake_queue(fi->dev);
 			}
 		}
 	}
@@ -2914,65 +2916,59 @@
 
 static int iph5526_open(struct net_device *dev)
 {
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	netif_start_queue(dev);
 	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int iph5526_close(struct net_device *dev)
 {
-	dev->tbusy = 1;
-	dev->start = 0;
+	netif_stop_queue(dev);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+static void iph5526_timeout(struct net_device *dev)
+{
+	struct fc_info *fi = (struct fc_info*)dev->priv;
+	printk(KERN_WARNING "%s: timed out on send.\n", dev->name);
+	fi->fc_stats.rx_dropped++;
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
 static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-struct fc_info *fi = (struct fc_info*)dev->priv;
-int status = 0;
-short type = 0;
-u_long flags;
+	struct fc_info *fi = (struct fc_info*)dev->priv;
+	int status = 0;
+	short type = 0;
+	u_long flags;
+	struct fcllc *fcllc;
+	
 	ENTER("iph5526_send_packet");
-	if (dev->tbusy) {
-		printk(KERN_WARNING "%s: DEVICE BUSY\n", dev->name);
-		dev->tbusy = 0;
-		fi->fc_stats.rx_dropped++;
-		dev->trans_start = jiffies;
-		return 0;
-	}
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", 
-dev->name);
-		fi->fc_stats.rx_dropped++;
-		return 1;
-	}
-	else {
-		struct fcllc *fcllc;
-		/* Strip off the pseudo header.
-		 */
-		skb->data = skb->data + 2*FC_ALEN; 
-		skb->len = skb->len - 2*FC_ALEN;
-		fcllc = (struct fcllc *)skb->data;
-		type = ntohs(fcllc->ethertype);
-
-		spin_lock_irqsave(&fi->fc_lock, flags);
-		switch(type) {
-			case ETH_P_IP:
-				status = tx_ip_packet(skb, skb->len, fi);
-				break;
-			case ETH_P_ARP:
-				status = tx_arp_packet(skb->data, skb->len, fi);
-				break;
-			default:
-				T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
-				fi->fc_stats.rx_dropped++;
-				break;
-		}
-		spin_unlock_irqrestore(&fi->fc_lock, flags);
+	
+	netif_stop_queue(dev);
+	/* Strip off the pseudo header.
+	 */
+	skb->data = skb->data + 2*FC_ALEN; 
+	skb->len = skb->len - 2*FC_ALEN;
+	fcllc = (struct fcllc *)skb->data;
+	type = ntohs(fcllc->ethertype);
+
+	spin_lock_irqsave(&fi->fc_lock, flags);
+	switch(type) {
+		case ETH_P_IP:
+			status = tx_ip_packet(skb, skb->len, fi);
+			break;
+		case ETH_P_ARP:
+			status = tx_arp_packet(skb->data, skb->len, fi);
+			break;
+		default:
+			T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
+			fi->fc_stats.rx_dropped++;
+			break;
 	}
+	spin_unlock_irqrestore(&fi->fc_lock, flags);
 
 	if (status) {
 		fi->fc_stats.tx_bytes += skb->len;
@@ -2981,14 +2977,14 @@
 	else
 		fi->fc_stats.rx_dropped++;
 	dev->trans_start = jiffies;
-	dev->tbusy = 0;
 	/* We free up the IP buffers in the OCI_interrupt handler.
 	 * status == 0 implies that the frame was not transmitted. So the
 	 * skb is freed here.
 	 */
 	if ((type == ETH_P_ARP) || (status == 0))
 		dev_kfree_skb(skb);
-	mark_bh(NET_BH);
+	else
+		netif_wake_queue(dev);
 	LEAVE("iph5526_send_packet");
 	return 0;
 }
diff -u --recursive --new-file v2.3.44/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.3.44/linux/drivers/net/fmv18x.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/fmv18x.c	Sun Feb 13 18:20:21 2000
@@ -58,8 +58,9 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 
-static int fmv18x_probe_list[] __initdata =
-{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
+static int fmv18x_probe_list[] __initdata = {
+	0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
+};
 
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
@@ -127,14 +128,8 @@
    If dev->base_addr == 2, allocate space for the device and return success
    (detachable devices only).
    */
-#ifdef HAVE_DEVLIST
-/* Support for an alternate probe manager, which will eliminate the
-   boilerplate below. */
-struct netdev_entry fmv18x_drv =
-{"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};
-#else
-int __init 
-fmv18x_probe(struct net_device *dev)
+
+int __init fmv18x_probe(struct net_device *dev)
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
@@ -154,7 +149,6 @@
 
 	return ENODEV;
 }
-#endif
 
 /* The Fujitsu datasheet suggests that the NIC be probed for by checking its
    "signature", the default bit pattern after a reset.  This *doesn't* work --
@@ -584,11 +578,6 @@
 static struct net_device_stats *net_get_stats(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-
-	cli();
-	/* ToDo: Update the statistics from the device registers. */
-	sti();
-
 	return &lp->stats;
 }
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/gmac.c linux/drivers/net/gmac.c
--- v2.3.44/linux/drivers/net/gmac.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/gmac.c	Sun Feb 13 10:47:01 2000
@@ -51,6 +51,7 @@
 	int		phy_addr;
 	int		full_duplex;
 	struct net_device_stats stats;
+	struct net_device *next_gmac;
 };
 
 #define GM_OUT(r, v)	out_le32(gm->regs + (r)/4, (v))
@@ -80,6 +81,7 @@
 static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static struct net_device_stats *gmac_stats(struct net_device *dev);
 static int gmac_probe(void);
+static void gmac_probe1(struct device_node *gmac);
 
 /* Stuff for talking to the physical-layer chip */
 static int
@@ -383,7 +385,7 @@
 	i = gm->next_tx;
 	if (gm->tx_buff[i] != 0) {
 		/* buffer is full, can't send this packet at the moment */
-		dev->tbusy = 1;
+		netif_stop_queue(dev);
 		gm->tx_full = 1;
 		restore_flags(flags);
 		return 1;
@@ -421,7 +423,7 @@
 		gm->stats.tx_bytes += skb->len;
 		++gm->stats.tx_packets;
 		gm->tx_buff[i] = NULL;
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		if (++i >= NTX)
 			i = 0;
 	}
@@ -452,7 +454,7 @@
 			++gm->stats.rx_dropped;
 		} else if (ld_le32(&dp->status) & 0x40000000) {
 			++gm->stats.rx_errors;
-			dev_kfree_skb(skb);
+			dev_kfree_skb_irq(skb);
 		} else {
 			skb_put(skb, len);
 			skb->dev = dev;
@@ -486,14 +488,11 @@
 	status = GM_IN(INTR_STATUS);
 	GM_OUT(INTR_ACK, status);
 	
-	if (status & GMAC_IRQ_MIF) {
+	if (status & GMAC_IRQ_MIF)
 		mii_interrupt(gm);
-	}
 	gmac_receive(dev);
-	if (gmac_tx_cleanup(gm)){
-		dev->tbusy = 0;
-		mark_bh(NET_BH);
-	}
+	if (gmac_tx_cleanup(gm))
+		netif_wake_queue(dev);
 }
 
 static struct net_device_stats *gmac_stats(struct net_device *dev)
@@ -505,33 +504,44 @@
 
 static int __init gmac_probe(void)
 {
-	static int gmacs_found;
-	static struct device_node *next_gmac;
 	struct device_node *gmac;
-	struct gmac *gm;
-	unsigned long descpage;
-	unsigned char *addr;
-	int i;
-
-	if (gmacs != NULL)
-		return -EBUSY;
 
 	/*
 	 * We could (and maybe should) do this using PCI scanning
 	 * for vendor/net_device ID 0x106b/0x21.
 	 */
-	if (!gmacs_found) {
-		next_gmac = find_compatible_devices("network", "gmac");
-		gmacs_found = 1;
-	}
-	if ((gmac = next_gmac) == 0)
-		return -ENODEV;
-	next_gmac = gmac->next;
+	for (gmac = find_compatible_devices("network", "gmac"); gmac != 0;
+	     gmac = gmac->next)
+		gmac_probe1(gmac);
+
+	return 0;
+}
+
+static void gmac_probe1(struct device_node *gmac)
+{
+	struct gmac *gm;
+	unsigned long descpage;
+	unsigned char *addr;
+	struct net_device *dev;
+	int i;
 
 	if (gmac->n_addrs < 1 || gmac->n_intrs < 1) {
 		printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n",
 		       gmac->full_name, gmac->n_addrs, gmac->n_intrs);
-		return -ENODEV;
+		return;
+	}
+
+	addr = get_property(gmac, "local-mac-address", NULL);
+	if (addr == NULL) {
+		printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
+		       gmac->full_name);
+		return;
+	}
+
+	descpage = get_free_page(GFP_KERNEL);
+	if (descpage == 0) {
+		printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
+		return;
 	}
 
 	dev = init_etherdev(0, sizeof(struct gmac));
@@ -544,13 +554,6 @@
 	gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
 	dev->irq = gmac->intrs[0].line;
 
-	addr = get_property(gmac, "local-mac-address", NULL);
-	if (addr == NULL) {
-		printk(KERN_ERR "Can't get mac-address for GMAC %s\n",
-		       gmac->full_name);
-		return -EAGAIN;
-	}
-
 	printk(KERN_INFO "%s: GMAC at", dev->name);
 	for (i = 0; i < 6; ++i) {
 		dev->dev_addr[i] = addr[i];
@@ -558,12 +561,6 @@
 	}
 	printk("\n");
 
-	descpage = get_free_page(GFP_KERNEL);
-	if (descpage == 0) {
-		printk(KERN_ERR "GMAC: can't get a page for descriptors\n");
-		return -EAGAIN;
-	}
-
 	gm->desc_page = descpage;
 	gm->rxring = (volatile struct gmac_dma_desc *) descpage;
 	gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800);
@@ -577,34 +574,29 @@
 
 	ether_setup(dev);
 
-	if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) {
+	if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev))
 		printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq);
-		return -EAGAIN;
-	}
 
+	gm->next_gmac = gmacs;
 	gmacs = dev;
-
-	return 0;
 }
 
-MODULE_AUTHOR("Paul Mackerras");
+MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt");
 MODULE_DESCRIPTION("PowerMac GMAC driver.");
 
-
 static void __exit gmac_cleanup_module(void)
 {
 	struct gmac *gm;
+	struct net_device *dev;
 
-	/* XXX should handle more than one */
-	if (gmacs == NULL)
-		return;
-
-	gm = (struct gmac *) gmacs->priv;
-	free_irq(gmacs->irq, gmac_interrupt);
-	free_page(gm->descpage);
-	unregister_netdev(gmacs);
-	kfree(gmacs);
-	gmacs = NULL;
+	while ((dev = gmacs) != NULL) {
+		gm = (struct gmac *) dev->priv;
+		gmacs = gm->next_gmac;
+		free_irq(dev->irq, dev);
+		free_page(gm->desc_page);
+		unregister_netdev(dev);
+		kfree(dev);
+	}
 }
 
 module_init(gmac_probe);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- v2.3.44/linux/drivers/net/hamradio/bpqether.c	Tue Nov 23 22:42:20 1999
+++ linux/drivers/net/hamradio/bpqether.c	Sun Feb 13 18:20:21 2000
@@ -222,7 +222,7 @@
 
 	dev = bpq_get_ax25_dev(dev);
 
-	if (dev == NULL || dev->start == 0) {
+	if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) {
 		kfree_skb(skb);
 		return 0;
 	}
@@ -275,7 +275,7 @@
 	 * Just to be *really* sure not to send anything if the interface
 	 * is down, the ethernet device may have gone.
 	 */
-	if (!dev->start) {
+	if (!test_bit(LINK_STATE_START, &dev->state)) {
 		bpq_check_devices(dev);
 		kfree_skb(skb);
 		return -ENODEV;
@@ -407,22 +407,15 @@
 {
 	if (bpq_check_devices(dev))
 		return -ENODEV;		/* oops, it's gone */
-
-	dev->tbusy = 0;
-	dev->start = 1;
-
 	MOD_INC_USE_COUNT;
-
+	netif_start_queue(dev);
 	return 0;
 }
 
 static int bpq_close(struct net_device *dev)
 {
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
 	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c
--- v2.3.44/linux/drivers/net/hamradio/dmascc.c	Wed Aug 18 11:38:51 1999
+++ linux/drivers/net/hamradio/dmascc.c	Sun Feb 13 18:20:21 2000
@@ -643,7 +643,6 @@
   }
 
   /* Initialize local variables */
-  dev->tbusy = 0;
   priv->rx_ptr = 0;
   priv->rx_over = 0;
   priv->rx_head = priv->rx_tail = priv->rx_count = 0;
@@ -732,7 +731,7 @@
   /* Configure PI2 DMA */
   if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);
 
-  dev->start = 1;
+  netif_start_queue(dev);
   info->open++;
   MOD_INC_USE_COUNT;
 
@@ -747,9 +746,8 @@
   int io = dev->base_addr;
   int cmd = priv->cmd;
 
-  dev->start = 0;
+  netif_stop_queue(dev);
   info->open--;
-  MOD_DEC_USE_COUNT;
 
   if (info->type == TYPE_TWIN)
     /* Drop DTR */
@@ -768,6 +766,7 @@
     if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);
     free_irq(dev->irq, info);
   }
+  MOD_DEC_USE_COUNT;
   return 0;
 }
 
@@ -779,16 +778,16 @@
   
   switch (cmd) {
   case SIOCGSCCPARAM:
-    rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));
-    if (rc) return rc;
-    copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));
+    if(copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param)))
+    	return -EFAULT;
     return 0;
   case SIOCSSCCPARAM:
-    if (!suser()) return -EPERM;
-    rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));
-    if (rc) return rc;
-    if (dev->start) return -EAGAIN;
-    copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));
+    if (!capable(CAP_NET_ADMIN)) 
+    	return -EPERM;
+    if (test_bit(LINK_STATE_START, &dev->state)) 
+    	return -EAGAIN;
+    if(copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)))
+    	return -EFAULT;
     dev->dma = priv->param.dma;
     return 0;
   default:
@@ -806,18 +805,8 @@
   int i;
 
   /* Block a timer-based transmit from overlapping */
-  if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
-    atomic_inc((void *) &priv->stats.tx_dropped);
-    dev_kfree_skb(skb);
-    return 0;
-  }
-
-  /* Return with an error if we cannot accept more data */
-  if (dev->tbusy) {
-    priv->tx_sem = 0;
-    return -1;
-  }
-
+  netif_stop_queue(dev);
+  
   /* Transfer data to DMA buffer */
   i = priv->tx_head;
   memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
@@ -829,7 +818,8 @@
   /* Set the busy flag if we just filled up the last buffer */
   priv->tx_head = (i + 1) % NUM_TX_BUF;
   priv->tx_count++;
-  if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;
+  if (priv->tx_count != NUM_TX_BUF)
+  	netif_wake_queue(dev);
 
   /* Set new TX state */
   if (priv->tx_state == TX_IDLE) {
@@ -1139,7 +1129,6 @@
     /* Remove frame from FIFO */
     priv->tx_tail = (i + 1) % NUM_TX_BUF;
     priv->tx_count--;
-    dev->tbusy = 0;
     /* Check if another frame is available and we are allowed to transmit */
     if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
       if (dev->dma) {
@@ -1171,7 +1160,7 @@
       priv->stats.tx_packets++;
     }
     /* Inform upper layers */
-    mark_bh(NET_BH);
+    netif_wake_queue(dev);
   }
 
   /* DCD transition */
diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.3.44/linux/drivers/net/hamradio/scc.c	Tue Nov 23 22:42:20 1999
+++ linux/drivers/net/hamradio/scc.c	Sun Feb 13 18:20:21 2000
@@ -317,12 +317,12 @@
 
 static inline void scc_lock_dev(struct scc_channel *scc)
 {
-	scc->dev->tbusy = 1;
+	netif_stop_queue(scc->dev);
 }
 
 static inline void scc_unlock_dev(struct scc_channel *scc)
 {
-	scc->dev->tbusy = 0;
+	netif_wake_queue(scc->dev);
 }
 
 static inline void scc_discard_buffers(struct scc_channel *scc)
@@ -1660,9 +1660,7 @@
  
 	init_channel(scc);
 
-	dev->tbusy = 0;
-	dev->start = 1;
-
+	netif_start_queue(dev);
 	return 0;
 }
 
@@ -1692,9 +1690,7 @@
 	
 	scc_discard_buffers(scc);
 
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
 	return 0;
 }
 
@@ -1727,7 +1723,7 @@
 	unsigned long flags;
 	char kisscmd;
 	
-	if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy)
+	if (scc == NULL || scc->magic != SCC_MAGIC)
 	{
 		dev_kfree_skb(skb);
 		return 0;
@@ -1753,7 +1749,7 @@
 		return 0;
 	}
 
-	save_flags(flags);
+	save_flags(flags); 
 	cli();
 	
 	if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len)
diff -u --recursive --new-file v2.3.44/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- v2.3.44/linux/drivers/net/hamradio/yam.c	Tue Nov 23 22:42:20 1999
+++ linux/drivers/net/hamradio/yam.c	Sun Feb 13 18:20:21 2000
@@ -649,7 +649,7 @@
 
 	for (i = 0; i < NR_PORTS; i++) {
 		struct net_device *dev = &yam_ports[i].dev;
-		if (dev->start)
+		if (test_bit(LINK_STATE_START, &dev->state))
 			yam_arbitrate(dev);
 	}
 	yam_timer.expires = jiffies + HZ / 100;
@@ -748,7 +748,7 @@
 		yp = &yam_ports[i];
 		dev = &yp->dev;
 
-		if (!dev->start)
+		if (!test_bit(LINK_STATE_START, &dev->state))
 			continue;
 
 		while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
@@ -794,7 +794,7 @@
 		if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
 			continue;
 		len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
-		len += sprintf(buffer + len, "  Up       %d\n", yam_ports[i].dev.start);
+		len += sprintf(buffer + len, "  Up       %d\n", test_bit(LINK_STATE_START, &yam_ports[i].dev.state));
 		len += sprintf(buffer + len, "  Speed    %u\n", yam_ports[i].bitrate);
 		len += sprintf(buffer + len, "  IoBase   0x%x\n", yam_ports[i].iobase);
 		len += sprintf(buffer + len, "  BaudRate %u\n", yam_ports[i].baudrate);
@@ -903,7 +903,9 @@
 	request_region(dev->base_addr, YAM_EXTENT, dev->name);
 
 	yam_set_uart(dev);
-	dev->start = 1;
+
+	netif_start_queue(dev);
+	
 	yp->slotcnt = yp->slot / 10;
 
 	/* Reset overruns for all ports - FPGA programming makes overruns */
@@ -935,8 +937,7 @@
 	/* Remove IRQ handler if last */
 	free_irq(dev->irq, NULL);
 	release_region(dev->base_addr, YAM_EXTENT);
-	dev->start = 0;
-	dev->tbusy = 1;
+	netif_stop_queue(dev);
 	while ((skb = skb_dequeue(&yp->send_queue)))
 		dev_kfree_skb(skb);
 
@@ -973,7 +974,7 @@
 		return -EINVAL;			/* unused */
 
 	case SIOCYAMSMCS:
-		if (dev->start)
+		if (test_bit(LINK_STATE_START, &dev->state))
 			return -EINVAL;		/* Cannot change this parameter when up */
 		ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
 		ym->bitrate = 9600;
@@ -989,13 +990,13 @@
 		if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
 			 return -EFAULT;
 
-		if ((yi.cfg.mask & YAM_IOBASE) && dev->start)
+		if ((yi.cfg.mask & YAM_IOBASE) && test_bit(LINK_STATE_START, &dev->state))
 			return -EINVAL;		/* Cannot change this parameter when up */
-		if ((yi.cfg.mask & YAM_IRQ) && dev->start)
+		if ((yi.cfg.mask & YAM_IRQ) && test_bit(LINK_STATE_START, &dev->state))
 			return -EINVAL;		/* Cannot change this parameter when up */
-		if ((yi.cfg.mask & YAM_BITRATE) && dev->start)
+		if ((yi.cfg.mask & YAM_BITRATE) && test_bit(LINK_STATE_START, &dev->state))
 			return -EINVAL;		/* Cannot change this parameter when up */
-		if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start)
+		if ((yi.cfg.mask & YAM_BAUDRATE) && test_bit(LINK_STATE_START, &dev->state))
 			return -EINVAL;		/* Cannot change this parameter when up */
 
 		if (yi.cfg.mask & YAM_IOBASE) {
@@ -1164,8 +1165,6 @@
 		dev->irq = yam_ports[i].irq;
 		dev->init = yam_probe;
 		dev->if_port = 0;
-		dev->start = 0;
-		dev->tbusy = 1;
 
 		if (register_netdev(dev)) {
 			printk(KERN_WARNING "yam: cannot register net  device %s\n", dev->name);
@@ -1211,7 +1210,7 @@
 		struct net_device *dev = &yam_ports[i].dev;
 		if (!dev->priv)
 			continue;
-		if (dev->start)
+		if (test_bit(LINK_STATE_START, &dev->state))
 			yam_close(dev);
 		unregister_netdev(dev);
 	}
diff -u --recursive --new-file v2.3.44/linux/drivers/net/hydra.c linux/drivers/net/hydra.c
--- v2.3.44/linux/drivers/net/hydra.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/hydra.c	Sun Feb 13 11:21:42 2000
@@ -175,17 +175,16 @@
 		}
 		strcpy(z->name, "Hydra Ethernet Card");
 
+		dev = init_etherdev(NULL, sizeof(struct hydra_private));
+		memset(dev->priv, 0, sizeof(struct hydra_private));
+    
 		for(j = 0; j < ETHER_ADDR_LEN; j++)
 			dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
     
 		printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
 			dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
 			dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-		init_etherdev(dev, 0);
-    
-		dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
-		memset(dev->priv, 0, sizeof(struct hydra_private));
-    
+
 		dev->base_addr = ZTWO_VADDR(base_addr);
 		dev->mem_start = ZTWO_VADDR(board);
 		dev->mem_end = dev->mem_start+0x4000;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.3.44/linux/drivers/net/mace.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/mace.c	Sun Feb 13 10:47:01 2000
@@ -20,9 +20,7 @@
 #include <asm/pgtable.h>
 #include "mace.h"
 
-#ifdef MODULE
 static struct net_device *mace_devs = NULL;
-#endif
 
 #define N_RX_RING	8
 #define N_TX_RING	6
@@ -55,6 +53,7 @@
     struct net_device_stats stats;
     struct timer_list tx_timeout;
     int timeout_active;
+    struct net_device *next_mace;
 };
 
 /*
@@ -67,6 +66,8 @@
 	+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
 
 static int bitrev(int);
+static int mace_probe(void);
+static void mace_probe1(struct device_node *mace);
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -99,34 +100,36 @@
     return d;
 }
 
-static int __init mace_probe (void)
+static int __init mace_probe(void)
+{
+	struct device_node *mace;
+
+	for (mace = find_devices("mace"); mace != NULL; mace = mace->next)
+		mace_probe1(mace);
+	return 0;
+}
+
+static void __init mace_probe1(struct device_node *mace)
 {
 	int j, rev;
 	struct net_device *dev;
 	struct mace_data *mp;
-	struct device_node *mace;
 	unsigned char *addr;
-	static int maces_found = 0;
-	static struct device_node *next_mace;
-
-#ifdef MODULE
-	if(mace_devs != NULL)
-		return -EBUSY;
-#endif
-
-	if (!maces_found) {
-		next_mace = find_devices("mace");
-		maces_found = 1;
-	}
-	mace = next_mace;
-	if (mace == 0)
-		return -ENODEV;
-	next_mace = mace->next;
 
 	if (mace->n_addrs != 3 || mace->n_intrs != 3) {
-		printk(KERN_ERR "can't use MACE %s: expect 3 addrs and 3 intrs\n",
+		printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
 		       mace->full_name);
-		return -ENODEV;
+		return;
+	}
+
+	addr = get_property(mace, "mac-address", NULL);
+	if (addr == NULL) {
+		addr = get_property(mace, "local-mac-address", NULL);
+		if (addr == NULL) {
+			printk(KERN_ERR "Can't get mac-address for MACE %s\n",
+			       mace->full_name);
+			return;
+		}
 	}
 
 	dev = init_etherdev(0, PRIV_BYTES);
@@ -138,16 +141,6 @@
 		ioremap(mace->addrs[0].address, 0x1000);
 	dev->irq = mace->intrs[0].line;
 
-	addr = get_property(mace, "mac-address", NULL);
-	if (addr == NULL) {
-		addr = get_property(mace, "local-mac-address", NULL);
-		if (addr == NULL) {
-			printk(KERN_ERR "Can't get mac-address for MACE at %lx\n",
-			       dev->base_addr);
-			return -EAGAIN;
-		}
-	}
-
 	printk(KERN_INFO "%s: MACE at", dev->name);
 	rev = addr[0] == 0 && addr[1] == 0xA0;
 	for (j = 0; j < 6; ++j) {
@@ -186,22 +179,17 @@
 
 	mace_reset(dev);
 
-	if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+	if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev))
 		printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
-		return -EAGAIN;
-	}
 	if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
-			dev)) {
+			dev))
 		printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
-		return -EAGAIN;
-	}
 	if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma",
-			dev)) {
+			dev))
 		printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
-		return -EAGAIN;
-	}
 
-	return 0;
+	mp->next_mace = mace_devs;
+	mace_devs = dev;
 }
 
 static void dbdma_reset(volatile struct dbdma_regs *dma)
@@ -365,9 +353,7 @@
     /* enable all interrupts except receive interrupts */
     out_8(&mb->imr, RCVINT);
 
-#ifdef MOD_INC_USE_COUNT
     MOD_INC_USE_COUNT;
-#endif
     return 0;
 }
 
@@ -406,9 +392,7 @@
 
     mace_clean_rings(mp);
 
-#ifdef MOD_DEC_USE_COUNT
     MOD_DEC_USE_COUNT;
-#endif
 
     return 0;
 }
@@ -683,7 +667,7 @@
 	    mp->stats.tx_bytes += mp->tx_bufs[i]->len;
 	    ++mp->stats.tx_packets;
 	}
-	dev_kfree_skb(mp->tx_bufs[i]);
+	dev_kfree_skb_irq(mp->tx_bufs[i]);
 	--mp->tx_active;
 	if (++i >= N_TX_RING)
 	    i = 0;
@@ -895,23 +879,25 @@
     }
 }
 
-
 MODULE_AUTHOR("Paul Mackerras");
 MODULE_DESCRIPTION("PowerMac MACE driver.");
 
 static void __exit mace_cleanup (void)
 {
-#ifdef MODULE
-    struct mace_data *mp = (struct mace_data *) mace_devs->priv;
-    unregister_netdev(mace_devs);
-
-    free_irq(mace_devs->irq, mace_interrupt);
-    free_irq(mp->tx_dma_intr, mace_txdma_intr);
-    free_irq(mp->rx_dma_intr, mace_rxdma_intr);
+    struct net_device *dev;
+    struct mace_data *mp;
 
-    kfree(mace_devs);
-    mace_devs = NULL;
-#endif
+    while ((dev = mace_devs) != 0) {
+	mp = (struct mace_data *) mace_devs->priv;
+	mace_devs = mp->next_mace;
+
+	free_irq(dev->irq, dev);
+	free_irq(mp->tx_dma_intr, dev);
+	free_irq(mp->rx_dma_intr, dev);
+
+	unregister_netdev(dev);
+	kfree(dev);
+    }
 }
 
 module_init(mace_probe);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c
--- v2.3.44/linux/drivers/net/ncr885e.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/ncr885e.c	Sun Feb 13 10:47:01 2000
@@ -11,9 +11,10 @@
  */
 
 static const char *version =
-"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n";
+"ncr885e.c:v1.0 02/10/00 dan@synergymicro.com, cort@fsmlabs.com\n";
 
 #include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -81,8 +82,6 @@
 
 int ncr885e_debug = NCR885E_DEBUG;
 static int print_version = 0;
-static int debug = NCR885E_DEBUG; /* module parm */
-
 
 struct ncr885e_private {
 
@@ -426,7 +425,6 @@
 	if ( xfer ) {
 
 		dev_kfree_skb( sp->tx_skbufs[i] );
-		mark_bh( NET_BH );
 
 		if ( txbits & TX_STATUS_TXOK ) {
 			sp->stats.tx_packets++;
@@ -443,7 +441,7 @@
 
 	}
 
-	dev->tbusy = 0;
+	netif_start_queue(dev);
   
 	return;
 }
@@ -626,12 +624,6 @@
 	sp = (struct ncr885e_private *) dev->priv;
 	spin_lock( &sp->lock );
   
-	if ( dev->interrupt ) {
-		printk( KERN_ERR "%s: Re-entering interrupt handler...\n", 
-			dev->name );
-	}
-
-	dev->interrupt = 1;
 	status = inw( ioaddr + INTERRUPT_CLEAR );
 
 	if (ncr885e_debug > 2)
@@ -671,7 +663,6 @@
 		ncr885e_rx( dev );
 	}
   
-	dev->interrupt = 0;
 	spin_unlock( &sp->lock );
 
 	return;
@@ -779,8 +770,7 @@
 
 	/* start anew from the beginning of the ring buffer (why not?) */
 	sp->tx_current = 0;
-	dev->tbusy = 0;
-	mark_bh( NET_BH );
+	netif_wake_queue(dev);
 
 	/* restart rx dma */
 	outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN,
@@ -958,9 +948,7 @@
 	outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
 	      ioaddr + RX_CHANNEL_CONTROL );
 
-	dev->start = 1;
-	dev->tbusy = 0;
-	dev->interrupt = 0;
+	netif_start_queue(dev);
 
 	MOD_INC_USE_COUNT;
 
@@ -990,7 +978,7 @@
 		next = 0;
 
 	/* mark ourselves as busy, even if we have too many packets waiting */
-	dev->tbusy = 1;
+	netif_stop_queue(dev);
 
 	/* see if it's necessary to defer this packet */
 	if ( sp->tx_active >= MAX_TX_ACTIVE ) {
@@ -1058,8 +1046,7 @@
 	struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
 	unsigned long ioaddr = dev->base_addr;
 
-	dev->start = 0;
-	dev->tbusy = 1;
+	netif_stop_queue(dev);
 
 	spin_lock( &np->lock );
 
@@ -1148,8 +1135,7 @@
  *  configuration.
  */
 
-static int
-ncr885e_probe1(unsigned long ioaddr, unsigned char irq )
+static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq )
 
 {
 	struct net_device *dev;
@@ -1158,9 +1144,6 @@
 	unsigned char *p;
 	int  i;
 
-	if (!request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name))
-		return -EBUSY;
-
 	dev = init_etherdev(NULL, 0 );
 
 	/* construct private data for the 885 ethernet */
@@ -1413,12 +1396,16 @@
 
 #endif /* NCR885E_DEBUG_MII */
 
-MODULE_AUTHOR("dan@synergymicro.com");
-MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver");
-MODULE_PARM(debug, "i");
+int
+init_module(void)
+{
+	if ( debug >= 0)
+		ncr885e_debug = debug;
 
+	return ncr885e_probe();
+}
 
-static void __exit ncr885e_cleanup (void)
+static void __exit cleanup_module(void)
 {
 	struct ncr885e_private *np;
 
@@ -1434,7 +1421,6 @@
 
 module_init(ncr885e_probe);
 module_exit(ncr885e_cleanup);
-
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.3.44/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v2.3.44/linux/drivers/net/ni65.c	Thu Feb 10 17:11:10 2000
+++ linux/drivers/net/ni65.c	Sun Feb 13 18:20:21 2000
@@ -228,6 +228,7 @@
 static int  ni65_lance_reinit(struct net_device *dev);
 static void ni65_init_lance(struct priv *p,unsigned char*,int,int);
 static int  ni65_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void  ni65_timeout(struct net_device *dev);
 static int  ni65_close(struct net_device *dev);
 static int  ni65_alloc_buffer(struct net_device *dev);
 static void ni65_free_buffer(struct priv *p);
@@ -278,16 +279,13 @@
 
 	if(ni65_lance_reinit(dev))
 	{
-		dev->tbusy     = 0;
-		dev->interrupt = 0;
-		dev->start     = 1;
+		netif_start_queue(dev);
 		MOD_INC_USE_COUNT;
 		return 0;
 	}
 	else
 	{
 		free_irq(dev->irq,dev);
-		dev->start = 0;
 		return -EAGAIN;
 	}
 }
@@ -299,6 +297,8 @@
 {
 	struct priv *p = (struct priv *) dev->priv;
 
+	netif_stop_queue(dev);
+	
 	outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
 
 #ifdef XMT_VIA_SKB
@@ -314,8 +314,6 @@
 	}
 #endif
 	free_irq(dev->irq,dev);
-	dev->tbusy = 1;
-	dev->start = 0;
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -482,15 +480,13 @@
 	dev->open		= ni65_open;
 	dev->stop		= ni65_close;
 	dev->hard_start_xmit	= ni65_send_packet;
+	dev->tx_timeout		= ni65_timeout;
+	dev->watchdog_timeo	= HZ/2;
 	dev->get_stats		= ni65_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
 	ether_setup(dev);
 
-	dev->interrupt		= 0;
-	dev->tbusy		= 0;
-	dev->start		= 0;
-
 	return 0; /* everything is OK */
 }
 
@@ -714,7 +710,8 @@
 		}
 		p->rmdnum = p->tmdlast = 0;
 		if(!p->lock)
-			dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
+			if (p->tmdnum || !p->xmit_queued)
+				netif_wake_queue(dev);
 		dev->trans_start = jiffies;
 	}
 	else
@@ -813,15 +810,6 @@
 	struct priv *p;
 	int bcnt = 32;
 
-	if (dev == NULL) {
-		printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
-
-	if(test_and_set_bit(0,(int *) &dev->interrupt)) {
-		printk("ni65: oops .. interrupt while proceeding interrupt\n");
-		return;
-	}
 	p = (struct priv *) dev->priv;
 
 	while(--bcnt) {
@@ -916,8 +904,6 @@
 	else
 		writedatareg(CSR0_INEA);
 
-	dev->interrupt = 0;
-
 	return;
 }
 
@@ -974,7 +960,7 @@
 
 #ifdef XMT_VIA_SKB
 		if(p->tmd_skb[p->tmdlast]) {
-			 dev_kfree_skb(p->tmd_skb[p->tmdlast]);
+			 dev_kfree_skb_irq(p->tmd_skb[p->tmdlast]);
 			 p->tmd_skb[p->tmdlast] = NULL;
 		}
 #endif
@@ -983,8 +969,7 @@
 		if(p->tmdlast == p->tmdnum)
 			p->xmit_queued = 0;
 	}
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
+	netif_wake_queue(dev);
 }
 
 /*
@@ -1082,32 +1067,31 @@
 /*
  * kick xmitter ..
  */
-static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
+ 
+static void ni65_timeout(struct net_device *dev)
 {
+	int i;
 	struct priv *p = (struct priv *) dev->priv;
 
-	if(dev->tbusy)
-	{
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 50)
-			return 1;
+	printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
+	for(i=0;i<TMDNUM;i++)
+		printk("%02x ",p->tmdhead[i].u.s.status);
+	printk("\n");
+	ni65_lance_reinit(dev);
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
 
-		printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
-		{
-			int i;
-			for(i=0;i<TMDNUM;i++)
-				printk("%02x ",p->tmdhead[i].u.s.status);
-			printk("\n");
-		}
-		ni65_lance_reinit(dev);
-		dev->tbusy=0;
-		dev->trans_start = jiffies;
-	}
+/*
+ *	Send a packet
+ */
 
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		 printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
-		 return 1;
-	}
+static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct priv *p = (struct priv *) dev->priv;
+
+	netif_stop_queue(dev);
+	
 	if (test_and_set_bit(0, (void*)&p->lock)) {
 		printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
 		return 1;
@@ -1152,7 +1136,9 @@
 		p->xmit_queued = 1;
 		p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
 
-		dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
+		if(p->tmdnum != p->tmdlast)
+			netif_wake_queue(dev);
+			
 		p->lock = 0;
 		dev->trans_start = jiffies;
 
@@ -1183,7 +1169,7 @@
 {
 	if(!ni65_lance_reinit(dev))
 		printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name);
-	dev->tbusy = 0;
+	netif_wake_queue(dev);
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/3c574_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/3c574_cs.c	Sun Feb 13 10:23:26 2000
@@ -220,6 +220,7 @@
 	u_short media_status;
 	u_short fast_poll;
 	u_long last_irq;
+	spinlock_t lock;
 };
 
 /* Set iff a MII transceiver on any interface requires mdio preamble.
@@ -261,6 +262,7 @@
 static int el3_close(struct net_device *dev);
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
 
 static dev_info_t dev_info = "3c574_cs";
 
@@ -320,6 +322,8 @@
 	lp = kmalloc(sizeof(*lp), GFP_KERNEL);
 	if (!lp) return NULL;
 	memset(lp, 0, sizeof(*lp));
+	
+	lp->lock = SPIN_LOCK_UNLOCKED;
 	link = &lp->link; dev = &lp->dev;
 	link->priv = dev->priv = link->irq.Instance = lp;
 	
@@ -351,7 +355,10 @@
 	dev->init = &tc574_init;
 	dev->open = &el3_open;
 	dev->stop = &el3_close;
-	dev->tbusy = 1;
+	dev->tx_timeout = el3_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	
+	netif_start_queue (dev);
 
 	/* Register with Card Services */
 	link->next = dev_list;
@@ -398,13 +405,12 @@
 	if (*linkp == NULL)
 	return;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lp->lock, flags);
 	if (link->state & DEV_RELEASE_PENDING) {
 		del_timer(&link->release);
 		link->state &= ~DEV_RELEASE_PENDING;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lp->lock, flags);
 
 	if (link->state & DEV_CONFIG) {
 		tc574_release((u_long)link);
@@ -502,7 +508,7 @@
 	dev->irq = link->irq.AssignedIRQ;
 	dev->base_addr = link->io.BasePort1;
 
-	dev->tbusy = 0;
+	netif_start_queue (dev);
 	if (register_netdev(dev) != 0) {
 		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
 		goto failed;
@@ -667,7 +673,7 @@
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			dev->tbusy = 1; dev->start = 0;
+			netif_stop_queue (dev);
 			link->release.expires = jiffies + HZ/20;
 			add_timer(&link->release);
 		}
@@ -682,7 +688,7 @@
 	case CS_EVENT_RESET_PHYSICAL:
 		if (link->state & DEV_CONFIG) {
 			if (link->open) {
-				dev->tbusy = 1; dev->start = 0;
+				netif_stop_queue (dev);
 			}
 			CardServices(ReleaseConfiguration, link->handle);
 		}
@@ -695,7 +701,7 @@
 			CardServices(RequestConfiguration, link->handle, &link->conf);
 			if (link->open) {
 				tc574_reset(dev);
-				dev->tbusy = 0; dev->start = 1;
+				netif_start_queue (dev);
 			}
 		}
 		break;
@@ -913,7 +919,7 @@
 	
 	link->open++;
 	MOD_INC_USE_COUNT;
-	dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+	netif_start_queue (dev);
 	
 	tc574_reset(dev);
 	lp->media.function = &media_check;
@@ -939,7 +945,7 @@
 	/* Issue TX_RESET and TX_START commands. */
 	wait_for_completion(dev, TxReset);
 	outw(TxEnable, ioaddr + EL3_CMD);
-	dev->tbusy = 0;
+	netif_start_queue (dev);
 }
 
 static void pop_tx_status(struct net_device *dev)
@@ -972,22 +978,16 @@
 	long flags = 0;
 #endif
 
-	/* Transmitter timeout, serious problems. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		if (jiffies - dev->trans_start < TX_TIMEOUT)
-			return 1;
-		el3_tx_timeout(dev);
-	}
-
 	DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
 		  "status %4.4x.\n", dev->name, (long)skb->len,
 		  inw(ioaddr + EL3_STATUS));
 
+	netif_stop_queue (dev);
+	
 #ifdef BROKEN_FEATURES
 	if (use_fifo_buffer) {
 		/* Avoid other accesses to the chip while RunnerWrCtrl is non-zero. */
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&lp->lock, flags);
 		outw((((skb->len + 7)>>2)<<1), ioaddr + RunnerWrCtrl);
 		DEBUG(0, "TxFree %x, tx length %x, RunnerWrCtrl is %4.4x.\n",
 			  inw(ioaddr+TxFree), skb->len, inw(ioaddr+RunnerWrCtrl));
@@ -1009,7 +1009,7 @@
 		DEBUG(0, " RunnerWr/RdCtrl is %4.4x/%4.4x, TxFree %x.\n",
 			  inw(ioaddr + RunnerWrCtrl), inw(ioaddr + RunnerRdCtrl),
 			  inw(ioaddr + TxFree));
-		restore_flags(flags);
+		spin_unlock_irqrestore (&lp->lock, flags);
 	}
 #else
 	outw(skb->len, ioaddr + TX_FIFO);
@@ -1021,7 +1021,7 @@
 
 	/* TxFree appears only in Window 1, not offset 0x1c. */
 	if (inw(ioaddr + TxFree) > 1536) {
-		dev->tbusy = 0;
+		netif_start_queue (dev);
 	} else
 		/* Interrupt us when the FIFO has room for max-sized packet. 
 		   The threshold is in units of dwords. */
@@ -1041,26 +1041,27 @@
 	ioaddr_t ioaddr, status;
 	int work_budget = max_interrupt_work;
 
-	if ((lp == NULL) || !dev->start)
+	if (lp == NULL)
 		return;
+
+	spin_lock (&lp->lock);
+
 	ioaddr = dev->base_addr;
 
 #ifdef PCMCIA_DEBUG
-	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-		printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
-			   dev->name);
-		return;
-	}
 	DEBUG(3, "%s: interrupt, status %4.4x.\n",
 		  dev->name, inw(ioaddr + EL3_STATUS));
 #endif
 
 	while ((status = inw(ioaddr + EL3_STATUS)) &
 		   (IntLatch | RxComplete | RxEarly | StatsFull)) {
+
+#if 0
 		if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) {
 			DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
 			break;
 		}
+#endif
 
 		if (status & RxComplete)
 			work_budget = el3_rx(dev, work_budget);
@@ -1069,8 +1070,9 @@
 			DEBUG(3, "  TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			dev->tbusy = 0;
-			mark_bh(NET_BH);
+			netif_wake_queue (dev);
+		} else {
+			netif_stop_queue (dev);
 		}
 
 		if (status & TxComplete)
@@ -1120,9 +1122,9 @@
 #ifdef PCMCIA_DEBUG
 	DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
 		  dev->name, inw(ioaddr + EL3_STATUS));
-	dev->interrupt = 0;
 #endif
-	return;
+
+	spin_unlock (&lp->lock);
 }
 
 /*
@@ -1138,7 +1140,9 @@
     u_long flags;
 	u_short /* cable, */ media, partner;
 	
+#if 0
     if (dev->start == 0) goto reschedule;
+#endif
 	
     /* Check for pending interrupt with expired latency timer: with
        this, we can limp along even if the interrupt is blocked */
@@ -1208,7 +1212,7 @@
 {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 
-	if (dev->start)
+	if (test_bit(LINK_STATE_START, &dev->state))
 		update_stats(dev);
 	return &lp->stats;
 }
@@ -1404,6 +1408,8 @@
 
 	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
 	
+	netif_stop_queue (dev);
+	
 	if (DEV_OK(link)) {
 		/* Turn off statistics ASAP.  We update lp->stats below. */
 		outw(StatsDisable, ioaddr + EL3_CMD);
@@ -1419,7 +1425,6 @@
 	}
 
 	link->open--;
-	dev->start = 0;
 	del_timer(&lp->media);
 	if (link->state & DEV_STALE_CONFIG) {
 		link->release.expires = jiffies + HZ/20;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c
--- v2.3.44/linux/drivers/net/pcmcia/3c575_cb.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/3c575_cb.c	Sun Feb 13 10:23:26 2000
@@ -53,18 +53,7 @@
 #error You must compile this driver with "-O".
 #endif
 
-#include <linux/config.h>
-#include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -89,13 +78,6 @@
 
 #include <linux/delay.h>
 
-#define PCI_SUPPORT_VER2
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-#if ! defined(CAP_NET_ADMIN)
-#define capable(CAP_XXX) (suser())
-#endif
-
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
 MODULE_PARM(debug, "i");
@@ -106,7 +88,6 @@
 MODULE_PARM(compaq_ioaddr, "i");
 MODULE_PARM(compaq_irq, "i");
 MODULE_PARM(compaq_device_id, "i");
-#endif
 
 /* Operational parameter that usually are not changed. */
 
@@ -209,15 +190,15 @@
 	const char *name;
 	u16	vendor_id, device_id, device_id_mask, flags;
 	int drv_flags, io_size;
-	struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
-							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
+	struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev,
+				     long ioaddr, int irq, int chip_idx, int fnd_cnt);
 };
 
 enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
 	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
-									struct net_device *dev, long ioaddr,
-									int irq, int dev_id, int card_idx);
+static struct net_device *vortex_probe1(struct pci_dev *pdev,
+					struct net_device *dev, long ioaddr,
+					int irq, int dev_id, int card_idx);
 static struct pci_id_info pci_tbl[] = {
 	{"3c590 Vortex 10Mbps",			0x10B7, 0x5900, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
@@ -427,7 +408,7 @@
 	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
 
 	/* PCI configuration space information. */
-	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */
+	struct pci_dev *pdev;
 	char *cb_fn_base;			/* CardBus function status addr space. */
 	int chip_id;
 
@@ -451,6 +432,7 @@
 	u16 advertising;					/* NWay media advertisement */
 	unsigned char phys[2];				/* MII device addresses. */
 	u16 deferred;
+	spinlock_t lock;
 };
 
 /* The action to take with a media selection timer tick.
@@ -501,7 +483,8 @@
 static struct net_device_stats *vortex_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void acpi_wake(int pci_bus, int pci_devfn);
+static void vortex_tx_timeout(struct net_device *dev);
+static void acpi_wake(struct pci_dev *pdev);
 static void acpi_set_WOL(struct net_device *dev);
 
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
@@ -542,20 +525,21 @@
 {
 	u16 dev_id, vendor_id;
 	u32 io;
-	u8 bus, devfn, irq;
+	u8 irq;
 	struct net_device *dev;
 	int chip_idx;
+	struct pci_dev *pdev;
 
 	vortex_reap();
 	if (loc->bus != LOC_PCI) return NULL;
-	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
-	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
+	if (!pdev) return NULL;
+	io = pci_resource_start (pdev, 0);
+	irq = pdev->irq;
+	vendor_id = pdev->vendor;
+	dev_id = pdev->device;
 	printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
-		   bus, devfn, dev_id);
-	io &= ~3;
+		   pdev->bus->number, pdev->devfn, dev_id);
 	if (io == 0 || irq == 0) {
 		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
 			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
@@ -572,7 +556,7 @@
 			   "vortex_attach().\n", vendor_id, dev_id);
 		return NULL;
 	}
-	dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
+	dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1);
 	if (dev) {
 		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
 		strcpy(node->dev_name, dev->name);
@@ -663,44 +647,6 @@
 	int cards_found = 0;
 
 	/* Allow an EISA-only driver. */
-#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
-	/* Ideally we would detect all cards in slot order.  That would
-	   be best done a central PCI probe dispatch, which wouldn't work
-	   well with the current structure.  So instead we detect 3Com cards
-	   in slot order. */
-	if (pcibios_present()) {
-		static int pci_index = 0;
-		unsigned char pci_bus, pci_device_fn;
-
-		for (;pci_index < 0xff; pci_index++) {
-			u16 vendor, device, pci_command, new_command;
-			int chip_idx, irq;
-			long ioaddr;
-
-			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-									&pci_bus, &pci_device_fn)
-				!= PCIBIOS_SUCCESSFUL)
-				break;
-			pcibios_read_config_word(pci_bus, pci_device_fn,
-									 PCI_VENDOR_ID, &vendor);
-			pcibios_read_config_word(pci_bus, pci_device_fn,
-									 PCI_DEVICE_ID, &device);
-			for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-				if (vendor == pci_tbl[chip_idx].vendor_id
-					&& (device & pci_tbl[chip_idx].device_id_mask) ==
-					pci_tbl[chip_idx].device_id)
-					break;
-			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
-				continue;
-
-			/* The Cyclone requires config space re-write if powered down. */
-			acpi_wake(pci_bus, pci_device_fn);
-
-			{
-				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-				ioaddr = pdev->resource[0].start;
-				irq = pdev->irq;
-#elif LINUX_VERSION_CODE >= 0x20155
 				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
 				ioaddr = pdev->base_address[0] & ~3;
 				irq = pdev->irq;
@@ -751,7 +697,6 @@
 			}
 		}
 	}
-#endif /* NO_PCI */
 
 	/* Now check all slots of the EISA bus. */
 	if (EISA_bus) {
@@ -787,9 +732,9 @@
 }
 #endif  /* ! Cardbus */
 
-static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
-									struct net_device *dev, long ioaddr,
-									int irq, int chip_idx, int card_idx)
+static struct net_device *vortex_probe1(struct pci_dev *pdev,
+					struct net_device *dev, long ioaddr,
+					int irq, int chip_idx, int card_idx)
 {
 	struct vortex_private *vp;
 	int option;
@@ -817,9 +762,9 @@
 	vp->next_module = root_vortex_dev;
 	root_vortex_dev = dev;
 
+	vp->lock = SPIN_LOCK_UNLOCKED;
 	vp->chip_id = chip_idx;
-	vp->pci_bus = pci_bus;
-	vp->pci_devfn = pci_devfn;
+	vp->pdev = pdev;
 
 	/* The lower four bits are the media type. */
 	if (dev->mem_start)
@@ -892,10 +837,9 @@
 
 	if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
 		u32 fn_st_addr;			/* Cardbus function status space */
-		pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
-								  &fn_st_addr);
+		fn_st_addr = pci_resource_start (pdev, 2);
 		if (fn_st_addr)
-			vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
+			vp->cb_fn_base = ioremap(fn_st_addr, 128);
 		printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
 			   dev->name, fn_st_addr, vp->cb_fn_base);
 	}
@@ -988,6 +932,8 @@
 	dev->get_stats = &vortex_get_stats;
 	dev->do_ioctl = &vortex_ioctl;
 	dev->set_multicast_list = &set_rx_mode;
+	dev->tx_timeout = vortex_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
 
 	return dev;
 }
@@ -1013,7 +959,7 @@
 	int i;
 	
 	/* Should be if(HAS_ACPI) */
-	acpi_wake(vp->pci_bus, vp->pci_devfn);
+	acpi_wake(vp->pdev);
 
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
@@ -1157,9 +1103,7 @@
 	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
 
 	vp->in_interrupt = 0;
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	netif_start_queue (dev);
 
 	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
 	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
@@ -1377,8 +1321,10 @@
 				 ioaddr + DownListPtr);
 		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
 			vp->tx_full = 0;
-			clear_bit(0, (void*)&dev->tbusy);
+			netif_start_queue (dev);
 		}
+		if (vp->tx_full)
+			netif_stop_queue (dev);
 		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
 		outw(DownUnstall, ioaddr + EL3_CMD);
 	} else
@@ -1478,12 +1424,8 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		if (jiffies - dev->trans_start >= TX_TIMEOUT)
-			vortex_tx_timeout(dev);
-		return 1;
-	}
-
+	netif_stop_queue (dev);
+	
 	/* Put out the doubleword header... */
 	outl(skb->len, ioaddr + TX_FIFO);
 	if (vp->bus_master) {
@@ -1496,9 +1438,9 @@
 	} else {
 		/* ... and the packet rounded to a doubleword. */
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		DEV_FREE_SKB(skb);
+		dev_kfree_skb (skb);
 		if (inw(ioaddr + TxFree) > 1536) {
-			clear_bit(0, (void*)&dev->tbusy);
+			netif_start_queue (dev);
 		} else
 			/* Interrupt us when the FIFO has room for max-sized packet. */
 			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
@@ -1535,11 +1477,8 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		if (jiffies - dev->trans_start >= TX_TIMEOUT)
-			vortex_tx_timeout(dev);
-		return 1;
-	} else {
+	netif_stop_queue (dev);
+	if (1) {
 		/* Calculate the next Tx descriptor entry. */
 		int entry = vp->cur_tx % TX_RING_SIZE;
 		struct boom_tx_desc *prev_entry =
@@ -1561,8 +1500,7 @@
 		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
 		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&vp->lock, flags);
 		/* Wait for the stall to complete. */
 		wait_for_completion(dev, DownStall);
 		prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
@@ -1571,16 +1509,17 @@
 			queued_packet++;
 		}
 		outw(DownUnstall, ioaddr + EL3_CMD);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&vp->lock, flags);
 
 		vp->cur_tx++;
-		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
+		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
 			vp->tx_full = 1;
-		else {					/* Clear previous interrupt enable. */
+			netif_stop_queue (dev);
+		} else {					/* Clear previous interrupt enable. */
 #if defined(tx_interrupt_mitigation)
 			prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
 #endif
-			clear_bit(0, (void*)&dev->tbusy);
+			netif_start_queue (dev);
 		}
 		dev->trans_start = jiffies;
 		return 0;
@@ -1597,23 +1536,8 @@
 	int latency, status;
 	int work_done = max_interrupt_work;
 
-#if defined(__i386__)
-	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-			   dev->name);
-		dev->interrupt = 0;	/* Avoid halting machine. */
-		return;
-	}
-#else
-	if (dev->interrupt) {
-		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-		return;
-	}
-	dev->interrupt = 1;
-#endif
-
-	dev->interrupt = 1;
+	spin_lock (&vp->lock);
+	
 	ioaddr = dev->base_addr;
 	latency = inb(ioaddr + Timer);
 	status = inw(ioaddr + EL3_STATUS);
@@ -1643,8 +1567,7 @@
 				printk(KERN_DEBUG "	TX room bit was handled.\n");
 			/* There's room in the FIFO for a full-sized packet. */
 			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			clear_bit(0, (void*)&dev->tbusy);
-			mark_bh(NET_BH);
+			netif_wake_queue (dev);
 		}
 
 		if (status & DownComplete) {
@@ -1657,7 +1580,7 @@
 					virt_to_bus(&vp->tx_ring[entry]))
 					break;			/* It still hasn't been processed. */
 				if (vp->tx_skbuff[entry]) {
-					DEV_FREE_SKB(vp->tx_skbuff[entry]);
+					dev_kfree_skb_irq(vp->tx_skbuff[entry]);
 					vp->tx_skbuff[entry] = 0;
 				}
 				/* vp->stats.tx_packets++;  Counted below. */
@@ -1666,19 +1589,21 @@
 			vp->dirty_tx = dirty_tx;
 			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
 				vp->tx_full = 0;
-				clear_bit(0, (void*)&dev->tbusy);
-				mark_bh(NET_BH);
+				netif_wake_queue (dev);
 			}
 		}
+		if (vp->tx_full)
+			netif_stop_queue (dev);
 		if (status & DMADone) {
 			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
 				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
+				dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */
 				if (inw(ioaddr + TxFree) > 1536) {
-					clear_bit(0, (void*)&dev->tbusy);
-					mark_bh(NET_BH);
-				} else /* Interrupt when FIFO has room for max-sized packet. */
+					netif_wake_queue (dev);
+				} else { /* Interrupt when FIFO has room for max-sized packet. */
 					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+					netif_stop_queue (dev);
+				}
 			}
 		}
 		/* Check for all uncommon interrupts at once. */
@@ -1715,12 +1640,7 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
 handler_exit:
-#if defined(__i386__)
-	clear_bit(0, (void*)&dev->interrupt);
-#else
-	dev->interrupt = 0;
-#endif
-	return;
+	spin_unlock (&vp->lock);
 }
 
 static int vortex_rx(struct net_device *dev)
@@ -1891,8 +1811,7 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	dev->start = 0;
-	dev->tbusy = 1;
+	netif_stop_queue (dev);
 
 	del_timer(&vp->timer);
 
@@ -1926,7 +1845,7 @@
 	long ioaddr = dev->base_addr;
 	int i;
 
-	if (dev->start)
+	if (test_bit(LINK_STATE_START, &dev->state))
 		vortex_down(dev);
 
 	if (vortex_debug > 1) {
@@ -1942,14 +1861,14 @@
 	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
 		for (i = 0; i < RX_RING_SIZE; i++)
 			if (vp->rx_skbuff[i]) {
-				DEV_FREE_SKB(vp->rx_skbuff[i]);
+				dev_kfree_skb(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
 	}
 	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
 		for (i = 0; i < TX_RING_SIZE; i++)
 			if (vp->tx_skbuff[i]) {
-				DEV_FREE_SKB(vp->tx_skbuff[i]);
+				dev_kfree_skb(vp->tx_skbuff[i]);
 				vp->tx_skbuff[i] = 0;
 			}
 	}
@@ -1964,11 +1883,10 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
 
-	if (dev->start) {
-		save_flags(flags);
-		cli();
+	if (test_bit(LINK_STATE_START, &dev->state)) {
+		spin_lock_irqsave (&vp->lock, flags);
 		update_stats(dev->base_addr, dev);
-		restore_flags(flags);
+		spin_unlock_irqrestore (&vp->lock, flags);
 	}
 	return &vp->stats;
 }
@@ -2168,35 +2086,35 @@
 	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
 	outw(RxEnable, ioaddr + EL3_CMD);
 	/* Change the power state to D3; RxEnable doesn't take effect. */
-	pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103);
+	pci_write_config_word(vp->pdev, 0xe0, 0x8103);
 }
 /* Change from D3 (sleep) to D0 (active).
    Problem: The Cyclone forgets all PCI config info during the transition! */
-static void acpi_wake(int bus, int devfn)
+static void acpi_wake(struct pci_dev *pdev)
 {
 	u32 base0, base1, romaddr;
 	u16 pci_command, pwr_command;
 	u8  pci_latency, pci_cacheline, irq;
 
-	pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command);
+	pci_read_config_word(pdev, 0xe0, &pwr_command);
 	if ((pwr_command & 3) == 0)
 		return;
-	pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command);
-	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0);
-	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1);
-	pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
-	pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency);
-	pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline);
-	pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq);
-
-	pcibios_write_config_word( bus, devfn, 0xe0, 0x0000);
-	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0);
-	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1);
-	pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr);
-	pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq);
-	pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency);
-	pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline);
-	pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5);
+	pci_read_config_word( pdev, PCI_COMMAND, &pci_command);
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0);
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1);
+	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr);
+	pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency);
+	pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+	pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq);
+
+	pci_write_config_word( pdev, 0xe0, 0x0000);
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0);
+	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1);
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr);
+	pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq);
+	pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency);
+	pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
+	pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5);
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/3c589_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/3c589_cs.c	Sun Feb 13 10:23:26 2000
@@ -155,6 +155,7 @@
 static struct net_device_stats *el3_get_stats(struct net_device *dev);
 static int el3_rx(struct net_device *dev);
 static int el3_close(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
 
 static void set_multicast_list(struct net_device *dev);
 
@@ -257,7 +258,10 @@
     dev->init = &tc589_init;
     dev->open = &el3_open;
     dev->stop = &el3_close;
-    dev->tbusy = 1;
+    dev->tx_timeout = el3_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+    
+    netif_start_queue (dev);
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -399,7 +403,7 @@
 	
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "3c589_cs: register_netdev() failed\n");
 	goto failed;
@@ -508,7 +512,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    dev->tbusy = 1; dev->start = 0;
+	    netif_stop_queue (dev);
 	    link->release.expires = jiffies + HZ/20;
 	    add_timer(&link->release);
 	}
@@ -523,7 +527,7 @@
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
 	    if (link->open) {
-		dev->tbusy = 1; dev->start = 0;
+		netif_stop_queue (dev);
 	    }
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
@@ -536,7 +540,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		tc589_reset(dev);
-		dev->tbusy = 0; dev->start = 1;
+		netif_start_queue (dev);
 	    }
 	}
 	break;
@@ -683,7 +687,7 @@
 
     link->open++;
     MOD_INC_USE_COUNT;
-    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    netif_start_queue (dev);
     
     tc589_reset(dev);
     lp->media.function = &media_check;
@@ -709,7 +713,7 @@
     /* Issue TX_RESET and TX_START commands. */
     wait_for_completion(dev, TxReset);
     outw(TxEnable, ioaddr + EL3_CMD);
-    dev->tbusy = 0;
+    netif_start_queue (dev);
 }
 
 static void pop_tx_status(struct net_device *dev)
@@ -739,22 +743,12 @@
 {
     ioaddr_t ioaddr = dev->base_addr;
 
-    /* Transmitter timeout, serious problems. */
-    if (dev->tbusy) {
-	if (jiffies - dev->trans_start < TX_TIMEOUT)
-	    return 1;
-	el3_tx_timeout(dev);
-    }
-
     DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
 	  "status %4.4x.\n", dev->name, (long)skb->len,
 	  inw(ioaddr + EL3_STATUS));
 
-    /* Avoid timer-based retransmission conflicts. */
-    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-	printk(KERN_NOTICE "%s: transmitter access conflict.\n",
-	       dev->name);
-    else {
+    netif_stop_queue (dev);
+    if (1) {
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	lp->stats.tx_bytes += skb->len;
 	/* Put out the doubleword header... */
@@ -765,7 +759,7 @@
 	
 	dev->trans_start = jiffies;
 	if (inw(ioaddr + TX_FREE) > 1536) {
-	    dev->tbusy = 0;
+	    netif_start_queue (dev);
 	} else
 	    /* Interrupt us when the FIFO has room for max-sized packet. */
 	    outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
@@ -785,7 +779,7 @@
     ioaddr_t ioaddr, status;
     int i = 0;
     
-    if ((lp == NULL) || !dev->start)
+    if (lp == NULL)
 	return;
     ioaddr = dev->base_addr;
 
@@ -802,10 +796,12 @@
     
     while ((status = inw(ioaddr + EL3_STATUS)) &
 	(IntLatch | RxComplete | StatsFull)) {
+#if 0
 	if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) {
 	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);
 	    break;
 	}
+#endif
 	
 	if (status & RxComplete)
 	    el3_rx(dev);
@@ -814,8 +810,9 @@
 	    DEBUG(3, "    TX room bit was handled.\n");
 	    /* There's room in the FIFO for a full-sized packet. */
 	    outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);
+	    netif_wake_queue (dev);
+	} else {
+	    netif_stop_queue (dev);
 	}
 	
 	if (status & TxComplete)
@@ -879,7 +876,9 @@
     u_short media, errs;
     u_long flags;
 
+#if 0
     if (dev->start == 0) goto reschedule;
+#endif
 
     EL3WINDOW(1);
     /* Check for pending interrupt with expired latency timer: with
@@ -1093,6 +1092,8 @@
     ioaddr_t ioaddr = dev->base_addr;
     
     DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
+    
+    netif_stop_queue (dev);
 
     if (DEV_OK(link)) {
 	/* Turn off statistics ASAP.  We update lp->stats below. */
@@ -1122,7 +1123,6 @@
     }
 
     link->open--;
-    dev->start = 0;
     del_timer(&lp->media);
     if (link->state & DEV_STALE_CONFIG) {
 	link->release.expires = jiffies + HZ/20;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/aironet4500_cs.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/net/pcmcia/aironet4500_cs.c	Sun Feb 13 10:23:26 2000
@@ -231,8 +231,7 @@
 	dev->init = &awc_pcmcia_init;
 	dev->open = &awc_pcmcia_open;
 	dev->stop = &awc_pcmcia_close;
-	dev->tbusy = 1;
-	dev->start  = 0;
+	netif_start_queue (dev);
 	
 	link->priv = dev;
 #if CS_RELEASE_CODE > 0x2911
@@ -567,7 +566,7 @@
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			dev->tbusy = 1; dev->start = 0;
+			netif_stop_queue (dev);
 			link->release.expires = RUN_AT( HZ/20 );
 			add_timer(&link->release);
 		}
@@ -582,7 +581,7 @@
 	case CS_EVENT_RESET_PHYSICAL:
 		if (link->state & DEV_CONFIG) {
 			if (link->open) {
-				dev->tbusy = 1; dev->start = 0;
+				netif_stop_queue (dev);
 			}
 			CardServices(ReleaseConfiguration, link->handle);
 		}
@@ -595,7 +594,7 @@
 			CardServices(RequestConfiguration, link->handle, &link->conf);
 			if (link->open) {
 				// awc_reset(dev);
-				dev->tbusy = 0; dev->start = 1;
+				netif_start_queue (dev);
 			}
 		}
 		break;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/fmvj18x_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Sun Feb 13 18:24:12 2000
@@ -115,6 +115,7 @@
 static void fjn_reset(struct net_device *dev);
 static struct net_device_stats *fjn_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
+static void fjn_tx_timeout (struct net_device *dev);
 
 static dev_info_t dev_info = "fmvj18x_cs";
 static dev_link_t *dev_list = NULL;
@@ -139,6 +140,7 @@
     cardtype_t cardtype;
     u_short sent;
     u_char mc_filter[8];
+    spinlock_t lock;
 } local_info_t;
 
 #define MC_FILTERBREAK 64
@@ -235,6 +237,8 @@
 #define INTR_OFF             0x0d /* LAN controler ignores interrupts */
 #define INTR_ON              0x1d /* LAN controler will catch interrupts */
 
+#define TX_TIMEOUT	     10
+
 /*======================================================================
 
     This bit of code is used to avoid unregistering network devices
@@ -278,6 +282,8 @@
     lp = kmalloc(sizeof(*lp), GFP_KERNEL);
     if (!lp) return NULL;
     memset(lp, 0, sizeof(*lp));
+    
+    lp->lock = SPIN_LOCK_UNLOCKED;
     link = &lp->link; dev = &lp->dev;
     link->priv = dev->priv = link->irq.Instance = lp;
 
@@ -314,7 +320,9 @@
     dev->init = &fmvj18x_init;
     dev->open = &fjn_open;
     dev->stop = &fjn_close;
-    dev->tbusy = 0xFF;
+    dev->tx_timeout = fjn_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+    netif_start_queue (dev);
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -462,7 +470,7 @@
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
 	goto failed;
@@ -585,8 +593,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    dev->tbusy = 0xFF; 
-	    dev->start = 0;
+	    netif_stop_queue (dev);
 	    link->release.expires = jiffies + HZ/20;
 	    add_timer(&link->release);
 	}
@@ -601,8 +608,7 @@
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
 	    if (link->open) {
-		dev->tbusy = 0xFF; 
-		dev->start = 0;
+	    	netif_stop_queue (dev);
 	    }
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
@@ -614,9 +620,8 @@
 	if (link->state & DEV_CONFIG) {
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
-		dev->tbusy = 0;
-		dev->start = 1;
 		fjn_reset(dev);
+		netif_start_queue (dev);
 	    }
 	}
 	break;
@@ -670,12 +675,9 @@
 	       "unknown device.\n", irq);
         return;
     }
-    if (dev->interrupt) {
-        printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
-	       dev->name);
-        return;
-    }
-    dev->interrupt = 1;
+    
+    spin_lock (&lp->lock);
+    
     ioaddr = dev->base_addr;
 
     /* avoid multiple interrupts */
@@ -708,71 +710,65 @@
 	    lp->tx_queue = 0;
 	    lp->tx_queue_len = 0;
 	    dev->trans_start = jiffies;
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);	/* Inform upper layers. */
+	    netif_wake_queue (dev);
 	} else {
 	    lp->tx_started = 0;
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);	/* Inform upper layers. */
+	    netif_stop_queue (dev);
 	}
     }
     DEBUG(4, "%s: exiting interrupt,\n", dev->name);
     DEBUG(4, "    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
 
-    dev->interrupt = 0;
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
-    return;
+    spin_unlock (&lp->lock);
+    
 } /* fjn_interrupt */
 
 /*====================================================================*/
-
-static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void fjn_tx_timeout (struct net_device *dev)
 {
-    struct local_info_t *lp = (struct local_info_t *)dev->priv;
-    ioaddr_t ioaddr = dev->base_addr;
-
-    if (dev->tbusy) {
-	/* If we get here, some higher level has decided we are broken.
-	   There should really be a "kick me" function call instead. */
-	int tickssofar = jiffies - dev->trans_start;
-	if (tickssofar < 10)
-	    return 1;
-	printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
-	       dev->name, htons(inw(ioaddr + TX_STATUS)),
-	       inb(ioaddr + TX_STATUS) & F_TMT_RDY
-	       ? "IRQ conflict" : "network cable problem");
-	printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
-	       "%04x %04x %04x %04x %04x.\n",
-	       dev->name, htons(inw(ioaddr + 0)),
-	       htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
-	       htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
-	       htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
-	       htons(inw(ioaddr +14)));
+	struct local_info_t *lp = (struct local_info_t *) dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	printk (KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+		dev->name, htons (inw (ioaddr + TX_STATUS)),
+		inb (ioaddr + TX_STATUS) & F_TMT_RDY
+		? "IRQ conflict" : "network cable problem");
+	printk (KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+		"%04x %04x %04x %04x %04x.\n",
+		dev->name, htons (inw (ioaddr + 0)),
+		htons (inw (ioaddr + 2)), htons (inw (ioaddr + 4)),
+		htons (inw (ioaddr + 6)), htons (inw (ioaddr + 8)),
+		htons (inw (ioaddr + 10)), htons (inw (ioaddr + 12)),
+		htons (inw (ioaddr + 14)));
 	lp->stats.tx_errors++;
+
 	/* ToDo: We should try to restart the adaptor... */
-	cli();
+	spin_lock_irqsave (&lp->lock, flags);
 
-	fjn_reset(dev);
+	fjn_reset (dev);
 
 	lp->tx_started = 0;
 	lp->tx_queue = 0;
 	lp->tx_queue_len = 0;
 	lp->sent = 0;
 	lp->open_time = jiffies;
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
-    
-	sti();
-    }
+	netif_start_queue (dev);
+
+	spin_unlock_irqrestore (&lp->lock, flags);
+}
+
+
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
 
-    /* Block a timer-based transmit from overlapping.  This could better be
-       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-	printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name);
-    else {
+    netif_stop_queue (dev);
+    if (1) {
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char *buf = skb->data;
 
@@ -806,17 +802,17 @@
 	    lp->tx_queue_len = 0;
 	    dev->trans_start = jiffies;
 	    lp->tx_started = 1;
-	    dev->tbusy = 0;
+	    netif_start_queue (dev);
 	} else {
 	    if( sram_config == 0 ) {
 		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
 		    /* Yes, there is room for one more packet. */
-		    dev->tbusy = 0;
+		    netif_start_queue (dev);
 	    } else {
 		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
 						lp->tx_queue < 127 )
 		    /* Yes, there is room for one more packet. */
-		    dev->tbusy = 0;
+		    netif_start_queue (dev);
 	    }
 	}
 
@@ -1025,9 +1021,7 @@
     lp->tx_queue = 0;
     lp->tx_queue_len = 0;
     lp->open_time = jiffies;
-    dev->interrupt = 0;
-    dev->tbusy = 0;
-    dev->start = 1;
+    netif_start_queue (dev);    
     
     MOD_INC_USE_COUNT;
 
@@ -1045,8 +1039,7 @@
     DEBUG(4, "fjn_close('%s').\n", dev->name);
 
     lp->open_time = 0;
-    dev->tbusy = 1;
-    dev->start = 0;
+    netif_stop_queue (dev);
 
     /* Set configuration register 0 to disable Tx and Rx. */
     if( sram_config == 0 ) 
@@ -1064,7 +1057,6 @@
 	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     link->open--;
-    dev->start = 0;
     if (link->state & DEV_STALE_CONFIG) {
 	link->release.expires = jiffies + HZ/20;
 	link->state |= DEV_RELEASE_PENDING;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/netwave_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/netwave_cs.c	Sun Feb 13 10:23:26 2000
@@ -151,7 +151,7 @@
 static const unsigned int txConfKey    = 0x02; /* Scramble data packets */
 static const unsigned int txConfLoop   = 0x01; /* Loopback mode */
 
-/*static int netwave_debug = 0;*/
+static int netwave_debug = 0;
 
 /*
    All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
@@ -223,6 +223,7 @@
 static int netwave_open(struct net_device *dev);  /* Open the device */
 static int netwave_close(struct net_device *dev); /* Close the device */
 static int netwave_config(struct net_device *dev, struct ifmap *map);
+static void netwave_tx_timeout (struct net_device *dev);
 
 /* Packet transmission and Packet reception */
 static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
@@ -308,6 +309,7 @@
     u_char     *ramBase;
     int        timeoutCounter;
     int        lastExec;
+    spinlock_t lock;
     struct timer_list      watchdog;	/* To avoid blocking state */
     struct site_survey     nss;
     struct enet_statistics stats;
@@ -454,6 +456,7 @@
     priv = kmalloc(sizeof(*priv), GFP_KERNEL);
     if (!priv) return NULL;
     memset(priv, 0, sizeof(*priv));
+    priv->lock = SPIN_LOCK_UNLOCKED;
     link = &priv->link; dev = &priv->dev;
     link->priv = dev->priv = priv;
     link->release.function = &netwave_release;
@@ -503,7 +506,9 @@
     dev->init = &netwave_init;
     dev->open = &netwave_open;
     dev->stop = &netwave_close;
-    dev->tbusy = 1;
+    dev->tx_timeout = netwave_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+    netif_start_queue (dev);
     link->irq.Instance = dev;
     
     /* Register with Card Services */
@@ -835,7 +840,7 @@
     struct net_device *dev = &priv->dev;
     tuple_t tuple;
     cisparse_t parse;
-    int i, j, last_ret, last_fn;
+    int i=0, j, last_ret, last_fn;
     u_char buf[64];
     win_req_t req;
     memreq_t mem;
@@ -910,7 +915,7 @@
     
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     if (register_netdev(dev) != 0) {
 	printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
 	goto failed;
@@ -1014,7 +1019,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    dev->tbusy = 1; dev->start = 0;
+	    netif_stop_queue (dev);
 	    link->release.expires = jiffies + 5;
 	    add_timer(&link->release);
 	}
@@ -1029,7 +1034,7 @@
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
 	    if (link->open) {
-		dev->tbusy = 1; dev->start = 0;
+		netif_stop_queue (dev);
 	    }
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
@@ -1042,7 +1047,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		netwave_reset(dev);
-		dev->tbusy = 0; dev->start = 1;
+		netif_start_queue (dev);
 	    }
 	}
 	break;
@@ -1229,6 +1234,18 @@
     return 0;
 }
 
+
+static void netwave_tx_timeout (struct net_device *dev)
+{
+	if (netwave_debug > 0)
+		printk (KERN_DEBUG "%s timed out.\n", dev->name);
+	netwave_reset (dev);
+	dev->trans_start = jiffies;
+	netif_start_queue (dev);
+}
+
+
+
 static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	/* This flag indicate that the hardware can't perform a transmission.
 	 * Theoritically, NET3 check it before sending a packet to the driver,
@@ -1236,29 +1253,6 @@
 	 * As the watchdog will abort too long transmissions, we are quite safe...
 	 */
 
-    if (dev->tbusy) {
-	/* Handled by watchdog */
-	return 1;
-		
-	/* If we get here, some higher level has decided we are broken.
-	   There should really be a 'kick me' function call instead.
-	   */
-	/*int tickssofar = jiffies - dev->trans_start;*/
-	/* printk("xmit called with busy. tickssofar %d\n", tickssofar); */
-	/*if (tickssofar < TX_TIMEOUT) 
-	  return 1;
-	  */
-	/* Should also detect if the kernel tries to xmit
-	 * on a stopped card. 
-	 */
-       
-	/*if (netwave_debug > 0)
-	  printk(KERN_DEBUG "%s timed out.\n", dev->name);
-	  netwave_reset(dev); 
-	  dev->trans_start = jiffies;
-	  dev->tbusy = 0;*/
-    }
-
     /* Sending a NULL skb means some higher layer thinks we've missed an
      * tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
      * itself. 
@@ -1268,15 +1262,14 @@
      * better be done with atomic_swap(1, dev->tbusy, but set_bit()
      * works as well 
      */
-    if ( test_and_set_bit(0, (void*)&dev->tbusy) != 0) 
-	printk("%s: Transmitter access conflict.\n", dev->name);
-    else {
+    netif_stop_queue (dev);
+    if (1) {
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char* buf = skb->data;
 	
 	if (netwave_hw_xmit( buf, length, dev) == 1) {
 	    /* Some error, let's make them call us another time? */
-	    dev->tbusy = 0;
+	    netif_start_queue (dev);
 	}
 	dev->trans_start = jiffies;
     }
@@ -1303,14 +1296,10 @@
     dev_link_t *link = &priv->link;
     int i;
     
-    if ((dev == NULL) | (!dev->start))
+    if (dev == NULL)
 	return;
     
-    if (dev->interrupt) {
-	printk("%s: re-entering the interrupt handler.\n", dev->name);
-	return;
-    }
-    dev->interrupt = 1;
+    spin_lock (&priv->lock);
     
     iobase = dev->base_addr;
     ramBase = priv->ramBase;
@@ -1409,8 +1398,7 @@
 	    /* If watchdog was activated, kill it ! */
 	    del_timer(&priv->watchdog);
 
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);
+	    netif_wake_queue (dev);
 	}
 	/* TxBA, this would trigger on all error packets received */
 	/* if (status & 0x01) {
@@ -1420,8 +1408,7 @@
 	   */
     }
     /* done.. */
-    dev->interrupt = 0;
-    return;
+    spin_unlock (&priv->lock);
 } /* netwave_interrupt */
 
 /*
@@ -1444,7 +1431,7 @@
     netwave_reset(dev); 
 	
     /* We are not waiting anymore... */
-    dev->tbusy = 0;
+    netif_start_queue (dev);
 	
 } /* netwave_watchdog */
 
@@ -1584,7 +1571,7 @@
     link->open++;
     MOD_INC_USE_COUNT;
 	
-    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    netif_start_queue (dev);
     netwave_reset(dev);
 	
     return 0;
@@ -1596,11 +1583,12 @@
 
     DEBUG(1, "netwave_close: finishing.\n");
 
+    netif_stop_queue (dev);
+
     /* If watchdog was activated, kill it ! */
     del_timer(&priv->watchdog);
 	
     link->open--;
-    dev->start = 0;
     if (link->state & DEV_STALE_CONFIG) {
 	link->release.expires = jiffies + 5;
 	link->state |= DEV_RELEASE_PENDING;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/nmclan_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/nmclan_cs.c	Sun Feb 13 10:23:26 2000
@@ -307,6 +307,10 @@
 #undef MACE_IMR_DEFAULT
 #define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
 
+#define TX_TIMEOUT (5*HZ)
+
+
+
 /* ----------------------------------------------------------------------------
 Type Definitions
 ---------------------------------------------------------------------------- */
@@ -360,6 +364,7 @@
     dev_link_t link;
     struct net_device dev;
     dev_node_t node;
+    spinlock_t lock;
     struct net_device_stats linux_stats; /* Linux statistics counters */
     mace_statistics mace_stats; /* MACE chip statistics counters */
 
@@ -432,6 +437,7 @@
 static struct net_device_stats *mace_get_stats(struct net_device *dev);
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
+static void mace_tx_timeout (struct net_device *dev);
 
 static void set_multicast_list(struct net_device *dev);
 
@@ -498,6 +504,8 @@
     lp = kmalloc(sizeof(*lp), GFP_KERNEL);
     if (!lp) return NULL;
     memset(lp, 0, sizeof(*lp));
+    
+    lp->lock = SPIN_LOCK_UNLOCKED;
     link = &lp->link; dev = &lp->dev;
     link->priv = dev->priv = link->irq.Instance = lp;
 
@@ -531,7 +539,10 @@
     dev->init = &nmclan_init;
     dev->open = &mace_open;
     dev->stop = &mace_close;
-    dev->tbusy = 0xFF;
+    dev->tx_timeout = mace_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+
+    netif_start_queue (dev);
 
     /* Register with Card Services */
     link->next = dev_list;
@@ -752,7 +763,7 @@
   CS_CHECK(RequestConfiguration, handle, &link->conf);
   dev->irq = link->irq.AssignedIRQ;
   dev->base_addr = link->io.BasePort1;
-  dev->tbusy = 0;
+  netif_start_queue (dev);
   i = register_netdev(dev);
   if (i != 0) {
     printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
@@ -859,7 +870,7 @@
     case CS_EVENT_CARD_REMOVAL:
       link->state &= ~DEV_PRESENT;
       if (link->state & DEV_CONFIG) {
-	dev->tbusy = 0xFF; dev->start = 0;
+	netif_stop_queue (dev);
 	link->release.expires = jiffies + HZ/20;
 	add_timer(&link->release);
       }
@@ -874,7 +885,7 @@
     case CS_EVENT_RESET_PHYSICAL:
       if (link->state & DEV_CONFIG) {
 	if (link->open) {
-	  dev->tbusy = 0xFF; dev->start = 0;
+	  netif_stop_queue (dev);
 	}
 	CardServices(ReleaseConfiguration, link->handle);
       }
@@ -886,9 +897,8 @@
       if (link->state & DEV_CONFIG) {
 	CardServices(RequestConfiguration, link->handle, &link->conf);
 	if (link->open) {
-	  dev->tbusy = 0;
-	  dev->start = 1;
 	  nmclan_reset(dev);
+	  netif_start_queue (dev);
 	}
       }
       break;
@@ -987,10 +997,7 @@
 
   MACEBANK(0);
 
-  dev->interrupt = 0;
-  dev->tbusy = 0;
-  dev->start = 1;
-
+  netif_start_queue (dev);
   nmclan_reset(dev);
 
   return 0; /* Always succeed */
@@ -1007,12 +1014,13 @@
   dev_link_t *link = &lp->link;
 
   DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+  
+  netif_stop_queue (dev);
 
   /* Mask off all interrupts from the MACE chip. */
   outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
 
   link->open--;
-  dev->start = 0;
   if (link->state & DEV_STALE_CONFIG) {
     link->release.expires = jiffies + HZ/20;
     link->state |= DEV_RELEASE_PENDING;
@@ -1024,6 +1032,24 @@
   return 0;
 } /* mace_close */
 
+
+static void mace_tx_timeout (struct net_device *dev)
+{
+	mace_private *lp = (mace_private *)dev->priv;
+	dev_link_t *link = &lp->link;
+
+	printk (KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+#if RESET_ON_TIMEOUT
+	printk ("resetting card\n");
+	CardServices (ResetCard, link->handle);
+#else				/* #if RESET_ON_TIMEOUT */
+	printk ("NOT resetting card\n");
+#endif				/* #if RESET_ON_TIMEOUT */
+	dev->trans_start = jiffies;
+	netif_start_queue (dev);
+}
+
+
 /* ----------------------------------------------------------------------------
 mace_start_xmit
 	This routine begins the packet transmit function.  When completed,
@@ -1038,39 +1064,11 @@
 {
   mace_private *lp = (mace_private *)dev->priv;
   ioaddr_t ioaddr = dev->base_addr;
-  dev_link_t *link = &lp->link;
-
-#if TIMEOUT_TX
-  /* Transmitter timeout. */
-  if (dev->tbusy) {
-    int tickssofar = jiffies - dev->trans_start;
-
-    if (tickssofar < (HZ/5))
-      return 1;
-    printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
-#if RESET_ON_TIMEOUT
-    printk("resetting card\n");
-    CardServices(ResetCard, link->handle);
-#else /* #if RESET_ON_TIMEOUT */
-    printk("NOT resetting card\n");
-#endif /* #if RESET_ON_TIMEOUT */
-    dev->trans_start = jiffies;
-    return 1;
-  }
-#else /* #if TIMEOUT_TX */
-  if (dev->tbusy)
-    return 1;
-#endif /* #if TIMEOUT_TX */
 
   DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n",
 	dev->name, (long)skb->len);
 
-  /* Avoid timer-based retransmission conflicts. */
-  if (test_and_set_bit(TBUSY_UNSPECIFIED, (void*)&dev->tbusy) != 0) {
-    printk(KERN_NOTICE "%s: transmitter access conflict.\n",
-	   dev->name);
-    return 1;
-  }
+  netif_stop_queue (dev);
 
 #if (!TX_INTERRUPTABLE)
   /* Disable MACE TX interrupts. */
@@ -1085,11 +1083,9 @@
        the upper layers.  The interrupt handler is guaranteed never to
        service a transmit interrupt while we are in here.
     */
-    set_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy);
 
     lp->linux_stats.tx_bytes += skb->len;
     lp->tx_free_frames--;
-    set_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
 
     /* WARNING: Write the _exact_ number of bytes written in the header! */
     /* Put out the word header [must be an outw()] . . . */
@@ -1105,11 +1101,10 @@
 
     if (lp->tx_free_frames > 0) {
 #if MULTI_TX
-      clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
+      netif_start_queue (dev);
 #endif /* #if MULTI_TX */
     }
 
-    clear_bit(TBUSY_PARTIAL_TX_FRAME, (void*)&dev->tbusy);
   }
 
 #if (!TX_INTERRUPTABLE)
@@ -1140,8 +1135,10 @@
 	  irq);
     return;
   }
+  
+  spin_lock (&lp->lock);
 
-  if (dev->interrupt || lp->tx_irq_disabled) {
+  if (lp->tx_irq_disabled) {
     printk(
       (lp->tx_irq_disabled?
        KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
@@ -1155,12 +1152,6 @@
     /* WARNING: MACE_IR has been read! */
     return;
   }
-  dev->interrupt = 1;
-
-  if (dev->start == 0) {
-    DEBUG(2, "%s: interrupt from dead card\n", dev->name);
-    goto exception;
-  }
 
   do {
     /* WARNING: MACE_IR is a READ/CLEAR port! */
@@ -1230,8 +1221,7 @@
 
       lp->linux_stats.tx_packets++;
       lp->tx_free_frames++;
-      clear_bit(TBUSY_NO_FREE_TX_FRAMES, (void*)&dev->tbusy);
-      mark_bh(NET_BH);
+      netif_wake_queue (dev);
     } /* if (status & MACE_IR_XMTINT) */
 
     if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) {
@@ -1266,8 +1256,7 @@
   } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
 
 exception:
-  dev->interrupt = 0;
-  return;
+  spin_unlock (&lp->lock);
 } /* mace_interrupt */
 
 /* ----------------------------------------------------------------------------
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/smc91c92_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Sun Feb 13 10:23:40 2000
@@ -125,6 +125,8 @@
     u_short			media_status;
     u_short			fast_poll;
     u_long			last_rx;
+    
+    spinlock_t			lock;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -281,6 +283,7 @@
 static int smc91c92_event(event_t event, int priority,
 			  event_callback_args_t *args);
 
+static void smc91c92_tx_timeout (struct net_device *dev);
 static int smc91c92_open(struct net_device *dev);
 static int smc91c92_close(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -379,9 +382,12 @@
     dev->init = &smc91c92_init;
     dev->open = &smc91c92_open;
     dev->stop = &smc91c92_close;
-    dev->tbusy = 1;
+    dev->tx_timeout = smc91c92_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
     dev->priv = link->priv = link->irq.Instance = smc;
     
+    netif_start_queue (dev);
+    
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -663,7 +669,7 @@
     struct smc_private *smc = link->priv;
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
-    int i, wait, loop;
+    int i, wait=0, loop;
     unsigned int addr;
 
     /* Read Ethernet address from Serial EEPROM */
@@ -775,7 +781,7 @@
     struct smc_private *smc = link->priv;
     struct net_device *dev = &smc->dev;
     static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
-    int i, j;
+    int i=0, j;
     
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
@@ -977,7 +983,7 @@
 	dev->if_port = if_port;
     else
 	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
@@ -1106,8 +1112,7 @@
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
 	if (link->state & DEV_CONFIG) {
-	    dev->tbusy = 1;
-	    dev->start = 0;
+	    netif_stop_queue (dev);
 	    link->release.expires = jiffies + HZ/20;
 	    link->state |= DEV_RELEASE_PENDING;
 	    add_timer(&link->release);
@@ -1123,7 +1128,7 @@
     case CS_EVENT_RESET_PHYSICAL:
 	if (link->state & DEV_CONFIG) {
 	    if (link->open) {
-		dev->tbusy = 1; dev->start = 0;
+		netif_stop_queue (dev);
 	    }
 	    CardServices(ReleaseConfiguration, link->handle);
 	}
@@ -1147,7 +1152,7 @@
 	    }
 	    if (link->open) {
 		smc_reset(dev);
-		dev->tbusy = 0;	dev->start = 1;
+		netif_start_queue (dev);
 	    }
 	}
 	break;
@@ -1201,7 +1206,7 @@
     link->open++;
     MOD_INC_USE_COUNT;
     
-    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    netif_start_queue (dev);
     smc->saved_skb = 0;
     smc->packets_waiting = 0;
     
@@ -1225,8 +1230,7 @@
     DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
 	  dev->name, inw(ioaddr + BANK_SELECT));
     
-    dev->tbusy = 1;
-    dev->start = 0;
+    netif_stop_queue (dev);
     
     /* Shut off all interrupts, and turn off the Tx and Rx sections.
        Don't bother to check for chip present. */
@@ -1240,7 +1244,7 @@
     SMC_SELECT_BANK( 1 );
     outw(CTL_POWERDOWN, ioaddr + CONTROL  );
     
-    link->open--; dev->start = 0;
+    link->open--;
     del_timer(&smc->media);
     if (link->state & DEV_STALE_CONFIG) {
 	link->release.expires = jiffies + HZ/20;
@@ -1281,7 +1285,7 @@
 	       " failed, status %#2.2x.\n", dev->name, packet_no);
 	dev_kfree_skb (skb);
 	smc->saved_skb = NULL;
-	dev->tbusy = 0;
+	netif_start_queue (dev);
 	return;
     }
     
@@ -1329,12 +1333,30 @@
     smc->saved_skb = NULL;
     dev_kfree_skb (skb);
     dev->trans_start = jiffies;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     return;
 }
 
 /*====================================================================*/
 
+static void smc91c92_tx_timeout (struct net_device *dev)
+{
+	struct smc_private *smc = dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+
+	printk (KERN_NOTICE "%s: SMC91c92 transmit timed out, "
+		"Tx_status %2.2x status %4.4x.\n",
+		dev->name, inw (ioaddr) & 0xff, inw (ioaddr + 2));
+	smc->stats.tx_errors++;
+	smc_reset (dev);
+	dev->trans_start = jiffies;
+	smc->saved_skb = NULL;
+	netif_start_queue (dev);
+}
+
+
+/*====================================================================*/
+
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
@@ -1342,29 +1364,10 @@
     unsigned short num_pages;
     short time_out, ir;
     
-    /* Transmitter timeout, serious problems. */
-    if (dev->tbusy) {
-	int tickssofar = jiffies - dev->trans_start;
-	if (tickssofar < TX_TIMEOUT)
-	    return 1;
-	printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
-	       "Tx_status %2.2x status %4.4x.\n",
-	       dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
-	smc->stats.tx_errors++;
-	smc_reset(dev);
-	dev->trans_start = jiffies;
-	dev->tbusy = 0;
-	smc->saved_skb = NULL;
-    }
-
     DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
 	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
-    
-    /* Avoid timer-based retransmission conflicts. */
-    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-	printk(KERN_ERR "%s: transmitter access conflict.\n", dev->name);
-	return 1;
-    }
+
+    netif_stop_queue (dev);
     
     if ( smc->saved_skb) {
 	/* THIS SHOULD NEVER HAPPEN. */
@@ -1500,18 +1503,13 @@
     u_short saved_bank, saved_pointer, mask, status;
     char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
 
-    if ((smc == NULL) || !dev->start)
+    if (smc == NULL)
 	return;
     ioaddr = dev->base_addr;
     
-#ifdef PCMCIA_DEBUG
-    if (dev->interrupt) {
-	printk(KERN_ERR "%s: re-entering the interrupt handler.\n",
-	       dev->name);
-	return;
-    }
-    dev->interrupt = 1;
+    spin_lock (&smc->lock);
 
+#ifdef PCMCIA_DEBUG
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
 	  irq, ioaddr);
 #endif
@@ -1569,7 +1567,7 @@
 	    mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
 	    
 	    /* and let the card send more packets to me */
-	    mark_bh( NET_BH );
+	    netif_wake_queue (dev);
 	}
 	if (status & IM_RX_OVRN_INT) {
 	    smc->stats.rx_errors++;
@@ -1588,8 +1586,9 @@
     outw(saved_pointer, ioaddr + POINTER);
     SMC_SELECT_BANK( saved_bank );
 
+    spin_unlock (&smc->lock);
+
 #ifdef PCMCIA_DEBUG
-    dev->interrupt = 0;
     DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
 #endif
 
@@ -1913,8 +1912,10 @@
     ioaddr_t ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
 
+#if 0
     if (dev->start == 0) goto reschedule;
-    
+#endif
+
     saved_bank = inw(ioaddr + BANK_SELECT);
     SMC_SELECT_BANK(2);
     i = inw(ioaddr + INTERRUPT);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c
--- v2.3.44/linux/drivers/net/pcmcia/tulip_cb.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/tulip_cb.c	Sun Feb 13 18:24:53 2000
@@ -96,16 +96,7 @@
 #endif
 
 #include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -128,7 +119,6 @@
 /* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
    This is only in the support-all-kernels source code. */
 
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
 MODULE_PARM(debug, "i");
@@ -138,14 +128,9 @@
 MODULE_PARM(csr0, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif
 
 #define RUN_AT(x) (jiffies + (x))
 
-#define NETSTATS_VER2
-#define PCI_SUPPORT_VER3
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-
 #define tulip_debug debug
 #ifdef TULIP_DEBUG
 static int tulip_debug = TULIP_DEBUG;
@@ -438,7 +423,8 @@
 	struct mediatable *mtable;
 	int cur_index;						/* Current media index. */
 	int saved_if_port;
-	unsigned char pci_bus, pci_devfn;
+	struct pci_dev *pdev;
+	spinlock_t lock;
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
@@ -515,9 +501,9 @@
     restore_flags(flags);
 }
 
-static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
-								   struct net_device *dev, long ioaddr, int irq,
-								   int chip_idx, int board_idx)
+static struct net_device *tulip_probe1(struct pci_dev *pdev,
+				       struct net_device *dev, long ioaddr, int irq,
+				       int chip_idx, int board_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct tulip_private *tp;
@@ -534,11 +520,11 @@
 
 	dev = init_etherdev(dev, 0);
 
-	pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
 	/* Bring the 21143 out of sleep mode.
 	   Caution: Snooze mode does not work with some boards! */
 	if (tulip_tbl[chip_idx].flags & HAS_ACPI)
-		pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000);
+		pci_write_config_dword(pdev, 0x40, 0x00000000);
 
 	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
 		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
@@ -691,8 +677,8 @@
 	memset(tp, 0, sizeof(*tp));
 	dev->priv = tp;
 
-	tp->pci_bus = pci_bus;
-	tp->pci_devfn = pci_devfn;
+	tp->lock = SPIN_LOCK_UNLOCKED;
+	tp->pdev = pdev;
 	tp->chip_id = chip_idx;
 	tp->revision = chip_rev;
 	tp->csr0 = csr0;
@@ -807,6 +793,8 @@
 #ifdef HAVE_MULTICAST
 	dev->set_multicast_list = &set_rx_mode;
 #endif
+	dev->tx_timeout = tulip_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
 
 	/* Reset the xcvr interface and turn on heartbeat. */
 	switch (chip_idx) {
@@ -1302,7 +1290,7 @@
 	udelay(2);
 
 	if (tulip_tbl[tp->chip_id].flags & HAS_ACPI)
-		pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0x00000000);
+		pci_write_config_dword(tp->pdev, 0x40, 0x00000000);
 
 	/* Clear the tx ring */
 	for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1461,15 +1449,13 @@
 	outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
 	outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id);
 
-	dev->tbusy = 0;
-	tp->interrupt = 0;
-	dev->start = 1;
-
 	/* Enable interrupts by setting the interrupt mask. */
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
 	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
 	outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
 	outl(0, ioaddr + CSR2);		/* Rx poll demand */
+	
+	netif_start_queue (dev);
 
 	if (tulip_debug > 2) {
 		printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
@@ -2354,8 +2340,8 @@
 	outl(0, ioaddr + CSR1);
 
 	dev->trans_start = jiffies;
+	netif_wake_queue (dev);
 	tp->stats.tx_errors++;
-	return;
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -2413,15 +2399,6 @@
 	int entry;
 	u32 flag;
 
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		if (jiffies - dev->trans_start < TX_TIMEOUT)
-			return 1;
-		tulip_tx_timeout(dev);
-		return 1;
-	}
-
 	/* Caution: the write order is important here, set the base address
 	   with the "ownership" bits last. */
 
@@ -2454,8 +2431,10 @@
 	tp->tx_ring[entry].length = skb->len | flag;
 	tp->tx_ring[entry].status = DescOwned;	/* Pass ownership to the chip. */
 	tp->cur_tx++;
-	if ( ! tp->tx_full)
-		clear_bit(0, (void*)&dev->tbusy);
+	if (tp->tx_full)
+		netif_stop_queue (dev);
+	else
+		netif_wake_queue (dev);
 
 	/* Trigger an immediate transmit demand. */
 	outl(0, dev->base_addr + CSR1);
@@ -2474,21 +2453,7 @@
 	long ioaddr = dev->base_addr;
 	int csr5, work_budget = max_interrupt_work;
 
-#if defined(__i386__) && defined(SMP_CHECK)
-	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-		printk(KERN_ERR "%s: Duplicate entry of the interrupt handler by "
-			   "processor %d.\n",
-			   dev->name, smp_processor_id());
-		dev->interrupt = 0;
-		return;
-	}
-#else
-	if (dev->interrupt) {
-		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-		return;
-	}
-	dev->interrupt = 1;
-#endif
+	spin_lock (&tp->lock);
 
 	do {
 		csr5 = inl(ioaddr + CSR5);
@@ -2549,7 +2514,7 @@
 				}
 
 				/* Free the original skb. */
-				dev_free_skb(tp->tx_skbuff[entry]);
+				dev_kfree_skb_irq(tp->tx_skbuff[entry]);
 				tp->tx_skbuff[entry] = 0;
 			}
 
@@ -2561,13 +2526,15 @@
 			}
 #endif
 
-			if (tp->tx_full && dev->tbusy
-				&& tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2) {
-				/* The ring is no longer full, clear tbusy. */
+			if (tp->tx_full && 
+			    tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2)
+				/* The ring is no longer full */
 				tp->tx_full = 0;
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
+			
+			if (tp->tx_full)
+				netif_stop_queue (dev);
+			else
+				netif_wake_queue (dev);
 
 			tp->dirty_tx = dirty_tx;
 			if (csr5 & TxDied) {
@@ -2630,12 +2597,7 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
 			   dev->name, inl(ioaddr + CSR5));
 
-#if defined(__i386__)
-	clear_bit(0, (void*)&dev->interrupt);
-#else
-	dev->interrupt = 0;
-#endif
-	return;
+	spin_unlock (&tp->lock);
 }
 
 static int
@@ -2751,8 +2713,7 @@
 	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 
-	dev->start = 0;
-	dev->tbusy = 1;
+	netif_stop_queue (dev);
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x00000000, ioaddr + CSR7);
@@ -2781,7 +2742,7 @@
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
 			   dev->name, inl(ioaddr + CSR5));
 
-	if (dev->start)
+	if (test_bit(LINK_STATE_START, &dev->state))
 		tulip_down(dev);
 
 	free_irq(dev->irq, dev);
@@ -2794,12 +2755,12 @@
 		tp->rx_ring[i].length = 0;
 		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
 		if (skb) {
-			dev_free_skb(skb);
+			dev_kfree_skb(skb);
 		}
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (tp->tx_skbuff[i])
-			dev_free_skb(tp->tx_skbuff[i]);
+			dev_kfree_skb(tp->tx_skbuff[i]);
 		tp->tx_skbuff[i] = 0;
 	}
 
@@ -2813,7 +2774,7 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	if (dev->start)
+	if (test_bit(LINK_STATE_START, &dev->state))
 		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
 
 	return &tp->stats;
@@ -3075,8 +3036,8 @@
 				tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
 			tp->tx_ring[entry].status = DescOwned;
 			if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
-				set_bit(0, (void*)&dev->tbusy);
 				tp->tx_full = 1;
+				netif_stop_queue (dev);
 			}
 			if (dummy >= 0)
 				tp->tx_ring[dummy].status = DescOwned;
@@ -3114,10 +3075,11 @@
 
 	printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
 
-	pci_set_master(pdev);
-	dev = tulip_probe1(pdev->bus->number, pdev->devfn, NULL,
-				       pdev->resource[0].start, pdev->irq,
-				       id->driver_data, board_idx++);
+	pci_enable_device (pdev);
+	pci_set_master (pdev);
+	dev = tulip_probe1(pdev, NULL,
+			   pci_resource_start (pdev, 0), pdev->irq,
+			   id->driver_data, board_idx++);
 	if (dev) {
 		pdev->driver_data = dev;
 		return 0;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Sun Feb 13 10:25:33 2000
@@ -66,31 +66,6 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Wrapper for disabling interrupts.
- */
-static inline unsigned long
-wv_splhi(void)
-{
-  unsigned long flags;
-
-  save_flags(flags);
-  cli();
-
-  return(flags);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wrapper for re-enabling interrupts.
- */
-static inline void
-wv_splx(unsigned long	flags)
-{
-  restore_flags(flags);
-}
-
-/*------------------------------------------------------------------*/
-/*
  * Wrapper for reporting error to cardservices
  */
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -581,20 +556,20 @@
 void wv_nwid_filter(unsigned char mode, net_local *lp)
 {
   mm_t                  m;
-  unsigned long         x;
+  unsigned long         flags;
   
 #ifdef WAVELAN_ROAMING_DEBUG
   printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name);
 #endif
   
   /* Disable interrupts & save flags */
-  x = wv_splhi();
+  spin_lock_irqsave (&lp->lock, flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
   /* ReEnable interrupts & restore flags */
-  wv_splx(x);
+  spin_unlock_irqrestore (&lp->lock, flags);
   
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
@@ -755,7 +730,7 @@
 {
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
-  unsigned long         x;
+  unsigned long         flags;
   
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
@@ -768,7 +743,7 @@
 #endif
  	
   /* Disable interrupts & save flags */
-  x = wv_splhi();
+  spin_lock_irqsave(&lp->lock, flags);
   
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
@@ -776,7 +751,7 @@
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  wv_splx(x);
+  spin_unlock_irqrestore (&lp->lock, flags);
   
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
@@ -863,15 +838,15 @@
   net_local *	lp = (net_local *)dev->priv;
   int		status;
   long		spin;
-  u_long	opri;
+  u_long	flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
   do
     {
-      opri = wv_splhi();
+      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      wv_splx(opri);
+      spin_unlock_irqrestore (&lp->lock, flags);
     }
   while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
 
@@ -1009,27 +984,25 @@
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void
-wv_82593_reconfig(device *	dev)
+static inline void wv_82593_reconfig (device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
+	net_local *lp = (net_local *) dev->priv;
+	dev_link_t *link = ((net_local *) dev->priv)->link;
 
-  /* Check if we can do it now ! */
-  if(!(link->open) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
-    {
-      lp->reconfig_82593 = TRUE;
+	/* Check if we can do it now ! */
+	if (!(link->open)) {
+		lp->reconfig_82593 = TRUE;
 #ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "%s: wv_82593_reconfig(): delayed (busy = %ld, link = %d)\n",
-	     dev->name, dev->tbusy, link->open);
+		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
+			dev->name, link->open);
 #endif
-    }
-  else
-    {
-      lp->reconfig_82593 = FALSE;
-      wv_82593_config(dev);
-      dev->tbusy = 0;
-    }
+	} else {
+		netif_stop_queue (dev);
+
+		lp->reconfig_82593 = FALSE;
+		wv_82593_config (dev);
+		netif_start_queue (dev);
+	}
 }
 
 #ifdef OLDIES
@@ -1286,9 +1259,6 @@
 wv_dev_show(device *	dev)
 {
   printk(KERN_DEBUG "dev:");
-  printk(" start=%d,", dev->start);
-  printk(" tbusy=%ld,", dev->tbusy);
-  printk(" interrupt=%d,", dev->interrupt);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1908,7 +1878,7 @@
   struct iwreq *	wrq = (struct iwreq *) rq;
   psa_t			psa;
   mm_t			m;
-  unsigned long		x;
+  unsigned long		flags;
   int			ret = 0;
 
 #ifdef DEBUG_IOCTL_TRACE
@@ -1916,7 +1886,7 @@
 #endif
 
   /* Disable interrupts & save flags */
-  x = wv_splhi();
+  spin_lock_irqsave (&lp->lock, flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -2528,7 +2498,7 @@
     }
 
   /* ReEnable interrupts & restore flags */
-  wv_splx(x);
+  spin_unlock_irqrestore (&lp->lock, flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2548,14 +2518,14 @@
   net_local *		lp = (net_local *) dev->priv;
   mmr_t			m;
   iw_stats *		wstats;
-  unsigned long		x;
+  unsigned long		flags;
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
   /* Disable interrupts & save flags */
-  x = wv_splhi();
+  spin_lock_irqsave (&lp->lock, flags);
 
   if(lp == (net_local *) NULL)
     return (iw_stats *) NULL;
@@ -2583,7 +2553,7 @@
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  wv_splx(x);
+  spin_unlock_irqrestore (&lp->lock, flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2917,7 +2887,7 @@
 {
   net_local *		lp = (net_local *) dev->priv;
   ioaddr_t		base = dev->base_addr;
-  unsigned long		x;
+  unsigned long		flags;
   int			clen = length;
   register u_short	xmtdata_base = TX_BASE;
 
@@ -2925,7 +2895,7 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  x = wv_splhi();
+  spin_lock_irqsave (&lp->lock, flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2963,7 +2933,7 @@
       add_timer(&lp->watchdog);
     }
 
-  wv_splx(x); 
+  spin_unlock_irqrestore (&lp->lock, flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2972,6 +2942,8 @@
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
+
+  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
@@ -2981,60 +2953,45 @@
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int
-wavelan_packet_xmit(struct sk_buff *	skb,
-		    device *		dev)
+static int wavelan_packet_xmit (struct sk_buff *skb,
+				device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
+	net_local *lp = (net_local *) dev->priv;
 
 #ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-	 (unsigned) skb);
+	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+		(unsigned) skb);
 #endif
 
-  /* This flag indicate that the hardware can't perform a transmission.
-   * Theoritically, NET3 check it before sending a packet to the driver,
-   * but in fact it never do that and pool continuously.
-   * As the watchdog will abort too long transmissions, we are quite safe...
-   */
-  if(dev->tbusy)
-    return(1);
+	/*
+	 * For ethernet, fill in the header.
+	 */
 
-  /*
-   * For ethernet, fill in the header.
-   */
-
-  /*
-   * Block a timer-based transmit from overlapping a previous transmit.
-   * In other words, prevent reentering this routine.
-   */
-  if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
-#ifdef DEBUG_TX_ERROR
-    printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
-#endif
-  else
-    {
-      /* If somebody has asked to reconfigure the controler, we can do it now */
-      if(lp->reconfig_82593)
-	{
-	  lp->reconfig_82593 = FALSE;
-	  wv_82593_config(dev);
-	}
+	netif_stop_queue (dev);
 
+	/*
+	 * Block a timer-based transmit from overlapping a previous transmit.
+	 * In other words, prevent reentering this routine.
+	 */
+	if (1) {
+		/* If somebody has asked to reconfigure the controler, we can do it now */
+		if (lp->reconfig_82593) {
+			lp->reconfig_82593 = FALSE;
+			wv_82593_config (dev);
+		}
 #ifdef DEBUG_TX_ERROR
-      if(skb->next)
-	printk(KERN_INFO "skb has next\n");
+		if (skb->next)
+			printk (KERN_INFO "skb has next\n");
 #endif
- 
-      wv_packet_write(dev, skb->data, skb->len);
-    }
 
-  dev_kfree_skb(skb);
+		wv_packet_write (dev, skb->data, skb->len);
+	}
+	dev_kfree_skb (skb);
 
 #ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-  return(0);
+	return (0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3245,7 +3202,8 @@
 wv_ru_stop(device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  unsigned long	opri;
+  net_local *lp = (net_local *) dev->priv;
+  unsigned long	flags;
   int		status;
   int		spin;
 
@@ -3262,10 +3220,10 @@
   do
     {
       udelay(10);
-      opri = wv_splhi();
+      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      wv_splx(opri);
+      spin_unlock_irqrestore (&lp->lock, flags);
     }
   while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
 
@@ -3273,10 +3231,10 @@
   do
     {
       udelay(10);
-      opri = wv_splhi();
+      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      wv_splx(opri);
+      spin_unlock_irqrestore (&lp->lock, flags);
     }
   while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
 
@@ -3347,16 +3305,16 @@
 #ifdef DEBUG_I82593_SHOW
   {
     int	status;
-    int	opri;
+    unsigned long flags;
     int	i = 0;
 
     /* spin until the chip starts receiving */
     do
       {
-	opri = wv_splhi();
+	spin_lock_irqsave (&lp->lock, flags);
 	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
 	status = inb(LCSR(base));
-	wv_splx(opri);
+	spin_unlock_irqrestore (&lp->lock, flags);
 	if(i++ > 10000)
 	  break;
       }
@@ -3838,7 +3796,7 @@
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      dev->tbusy = 0;
+      netif_start_queue (dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3991,13 +3949,7 @@
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  /* Prevent reentrance. What should we do here ? */
-#ifdef DEBUG_INTERRUPT_ERROR
-  if(dev->interrupt)
-    printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
-	   dev->name);
-#endif
-  dev->interrupt = 1;
+  spin_lock (&lp->lock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4201,8 +4153,7 @@
 	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
 	  lp->stats.tx_packets++;
 
-	  dev->tbusy = FALSE;
-	  mark_bh(NET_BH);
+	  netif_wake_queue (dev);
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	} 
       else	/* if interrupt = transmit done or retransmit done */
@@ -4214,7 +4165,8 @@
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	}
     }
-  dev->interrupt = FALSE;
+
+  spin_unlock_irq (&lp->lock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4296,7 +4248,7 @@
 #endif
 
   /* We are no more waiting for something... */
-  dev->tbusy = 0;
+  netif_start_queue (dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4349,9 +4301,7 @@
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);		/* If problem : reset */
-  dev->interrupt = 0;
-  dev->start = 1;
-  dev->tbusy = 0;   
+  netif_start_queue (dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4385,6 +4335,8 @@
 	 (unsigned int) dev);
 #endif
 
+  netif_stop_queue (dev);
+
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4408,10 +4360,9 @@
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if(dev->start)
+  if (test_bit(LINK_STATE_START, &dev->state))
     {
-      dev->tbusy = 1;
-      dev->start = 0;
+      netif_stop_queue (dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4549,7 +4500,7 @@
   /* Other specific data */
   /* Provide storage area for device name */
   dev->name = ((net_local *)dev->priv)->node.dev_name;
-  dev->tbusy = 1;
+  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4711,7 +4662,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    dev->tbusy = 1; dev->start = 0;
+      	    netif_stop_queue (dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4749,8 +4700,7 @@
 	  {
       	    if(link->open)
 	      {
-		dev->tbusy = 1;
-		dev->start = 0;
+	      	netif_stop_queue (dev);
 	      }
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
@@ -4766,8 +4716,7 @@
       	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
 	      {
 		wv_hw_reset(dev);
-		dev->tbusy = 0;
-		dev->start = 1;
+		netif_start_queue (dev);
 	      }
 	  }
 	break;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.3.44/linux/drivers/net/pcmcia/wavelan_cs.h	Mon Dec 20 18:48:21 1999
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Sun Feb 13 10:25:33 2000
@@ -550,6 +550,7 @@
  */
 struct net_local
 {
+  spinlock_t	lock;
   dev_node_t 	node;		/* ???? What is this stuff ???? */
   device *	dev;		/* Reverse link... */
   dev_link_t *	link;		/* pcmcia structure */
@@ -609,10 +610,6 @@
 #endif	/* WAVELAN_ROAMING */
 
 /* ----------------------- MISC SUBROUTINES ------------------------ */
-static inline unsigned long	/* flags */
-	wv_splhi(void);		/* Disable interrupts */
-static inline void
-	wv_splx(unsigned long);	/* ReEnable interrupts : flags */
 static void
 	cs_error(client_handle_t, /* Report error to cardmgr */
 		 int,
diff -u --recursive --new-file v2.3.44/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- v2.3.44/linux/drivers/net/pcmcia/xirc2ps_cs.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Sun Feb 13 10:25:33 2000
@@ -410,6 +410,7 @@
     int suspended;
     unsigned last_ptr_value; /* last packets transmitted value */
     const char *manf_str;
+    spinlock_t lock;
 } local_info_t;
 
 /****************
@@ -429,6 +430,7 @@
 static int init_mii(struct net_device *dev);
 static void do_powerdown(struct net_device *dev);
 static int do_stop(struct net_device *dev);
+static void xirc_tx_timeout (struct net_device *dev);
 
 /*=============== Helper functions =========================*/
 static void
@@ -691,6 +693,8 @@
     local = kmalloc(sizeof(*local), GFP_KERNEL);
     if (!local) return NULL;
     memset(local, 0, sizeof(*local));
+    
+    local->lock = SPIN_LOCK_UNLOCKED;
     link = &local->link; dev = &local->dev;
     link->priv = dev->priv = local;
 
@@ -717,7 +721,9 @@
     dev->init = &do_init;
     dev->open = &do_open;
     dev->stop = &do_stop;
-    dev->tbusy = 1;
+    dev->tx_timeout = xirc_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+    netif_start_queue (dev);
 
     /* Register with Card Services */
     link->next = dev_list;
@@ -1233,7 +1239,7 @@
     /* we can now register the device with the net subsystem */
     dev->irq = link->irq.AssignedIRQ;
     dev->base_addr = link->io.BasePort1;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     if ((err=register_netdev(dev))) {
 	printk(KNOT_XIRC "register_netdev() failed\n");
 	goto config_error;
@@ -1334,7 +1340,7 @@
       case CS_EVENT_CARD_REMOVAL:
 	  link->state &= ~DEV_PRESENT;
 	  if (link->state & DEV_CONFIG) {
-	      dev->tbusy = 1; dev->start = 0;
+	      netif_stop_queue (dev);
 	      link->release.expires = jiffies + HZ / 20;
 	      add_timer(&link->release);
 	  }
@@ -1349,7 +1355,7 @@
       case CS_EVENT_RESET_PHYSICAL:
 	  if (link->state & DEV_CONFIG) {
 	      if (link->open) {
-		  dev->tbusy = 1; dev->start = 0;
+		  netif_stop_queue (dev);
 		  lp->suspended=1;
 		  do_powerdown(dev);
 	      }
@@ -1365,7 +1371,7 @@
 	     if (link->open) {
 		 do_reset(dev,1);
 		 lp->suspended=0;
-		 dev->tbusy = 0; dev->start = 1;
+		 netif_start_queue (dev);
 	     }
 	  }
 	  break;
@@ -1393,14 +1399,8 @@
 				  * -- on a laptop?
 				  */
 
-    if (!dev->start)
-       return;
+    spin_lock (&lp->lock);
 
-    if (dev->interrupt) {
-	printk(KERR_XIRC "re-entering isr on irq %d (dev=%p)\n", irq, dev);
-	return;
-    }
-    dev->interrupt = 1;
     ioaddr = dev->base_addr;
     if (lp->mohawk) { /* must disable the interrupt */
 	PutByte(XIRCREG_CR, 0);
@@ -1555,8 +1555,7 @@
 	    DEBUG(0, "PTR not changed?\n");
 	} else
 	    lp->stats.tx_packets += lp->last_ptr_value - n;
-	dev->tbusy = 0;
-	mark_bh(NET_BH);  /* Inform upper layers. */
+	netif_wake_queue (dev);
     }
     if (tx_status & 0x0002) {	/* Execessive collissions */
 	DEBUG(0, "tx restarted due to execssive collissions\n");
@@ -1595,7 +1594,9 @@
 	    goto loop_entry;
     }
     SelectPage(saved_page);
-    dev->interrupt = 0;
+
+    spin_unlock (&lp->lock);
+
     PutByte(XIRCREG_CR, EnableIntr);  /* re-enable interrupts */
     /* Instead of dropping packets during a receive, we could
      * force an interrupt with this command:
@@ -1605,44 +1606,39 @@
 
 /*====================================================================*/
 
-static int
-do_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void xirc_tx_timeout (struct net_device *dev)
 {
-    local_info_t *lp = dev->priv;
-    ioaddr_t ioaddr = dev->base_addr;
-    int okay;
-    unsigned freespace;
-    unsigned pktlen = skb? skb->len : 0;
-
-    DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
-	  skb, dev, pktlen);
-
-    /* Transmitter timeout, serious problems */
-    if (dev->tbusy) {
-	int tickssofar = jiffies - dev->trans_start;
+	local_info_t *lp = dev->priv;
 
 	if (lp->suspended) {
-	    dev_kfree_skb (skb);
 	    dev->trans_start = jiffies;
 	    lp->stats.tx_dropped++;
-	    return 0;
+	    netif_start_queue (dev);
+	    return;
 	}
-	if (tickssofar < TX_TIMEOUT)
-	    return 1;
 
 	printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
 	lp->stats.tx_errors++;
 	/* reset the card */
 	do_reset(dev,1);
 	dev->trans_start = jiffies;
-	dev->tbusy = 0;
-    }
+	netif_start_queue (dev);
+}
 
-    if (test_and_set_bit(0, (void*)&dev->tbusy)) {
-	printk(KWRN_XIRC "transmitter access conflict\n");
-	dev_kfree_skb (skb);
-	return 0;
-    }
+
+static int
+do_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int okay;
+    unsigned freespace;
+    unsigned pktlen = skb? skb->len : 0;
+
+    DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
+	  skb, dev, pktlen);
+
+    netif_stop_queue (dev);
 
     /* adjust the packet length to min. required
      * and hope that the buffer is large enough
@@ -1664,7 +1660,6 @@
     DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n",
 	  dev->name, freespace, okay ? " (okay)":" (not enough)");
     if (!okay) { /* not enough space */
-	dev->tbusy = 1;
 	return 1;  /* upper layer may decide to requeue this packet */
     }
     /* send the packet */
@@ -1678,7 +1673,7 @@
 
     dev_kfree_skb (skb);
     dev->trans_start = jiffies;
-    dev->tbusy = 0;
+    netif_start_queue (dev);
     lp->stats.tx_bytes += pktlen;
     return 0;
 }
@@ -1823,7 +1818,7 @@
     link->open++;
     MOD_INC_USE_COUNT;
 
-    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    netif_start_queue (dev);
     lp->suspended = 0;
     do_reset(dev,1);
 
@@ -2141,8 +2136,7 @@
     if (!link)
 	return -ENODEV;
 
-    dev->tbusy = 1;
-    dev->start = 0;
+    netif_stop_queue (dev);
 
     SelectPage(0);
     PutByte(XIRCREG_CR, 0);  /* disable interrupts */
@@ -2152,7 +2146,7 @@
     PutByte(XIRCREG4_GPR1, 0);	/* clear bit 0: power down */
     SelectPage(0);
 
-    link->open--; dev->start = 0;
+    link->open--;
     if (link->state & DEV_STALE_CONFIG) {
 	link->release.expires = jiffies + HZ/20;
 	link->state |= DEV_RELEASE_PENDING;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.3.44/linux/drivers/net/rcpci45.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/rcpci45.c	Sat Feb 12 15:45:05 2000
@@ -309,7 +309,6 @@
 #endif
     dev->base_addr = (unsigned long)vaddr;
     dev->irq = irq;
-    dev->interrupt = 0;
 
     /*
      * Request a shared interrupt line.
@@ -430,6 +429,7 @@
     printk("rc: RCopen: posted %d buffers\n", (uint)pDpa->numOutRcvBuffers);
 #endif
     MOD_INC_USE_COUNT;
+    netif_start_queue(dev);
     return 0;
 }
 
@@ -441,29 +441,26 @@
     singleTCB tcb;
     psingleTCB ptcb = &tcb;
     RC_RETURN status = 0;
-    
-        if (dev->tbusy || pDpa->shutdown || pDpa->reboot)
-        {
+   
+    netif_stop_queue(dev);
+     
+    if (pDpa->shutdown || pDpa->reboot)
+    {
 #ifdef RCDEBUG
             printk("rc: RC_xmit_packet: tbusy!\n");
 #endif
-            dev->tbusy = 1;
             return 1;
-        }
-      
-    if ( skb->len <= 0 ) 
-    {
-        printk("RC_xmit_packet: skb->len less than 0!\n");
-        return 0;
     }
-
+      
     /*
      * The user is free to reuse the TCB after RCI2OSendPacket() returns, since
      * the function copies the necessary info into its own private space.  Thus,
      * our TCB can be a local structure.  The skb, on the other hand, will be
      * freed up in our interrupt handler.
      */
+
     ptcb->bcount = 1;
+
     /* 
      * we'll get the context when the adapter interrupts us to tell us that
      * the transmision is done. At that time, we can free skb.
@@ -483,13 +480,12 @@
 #ifdef RCDEBUG
         printk("rc: RC send error 0x%x\n", (uint)status);
 #endif
-        dev->tbusy = 1;
         return 1;
     }
     else
     {
         dev->trans_start = jiffies;
-        //       dev->tbusy = 0;
+        netif_wake_queue(dev);
     }
     /*
      * That's it!
@@ -546,10 +542,9 @@
             printk("rc: skb = 0x%x\n", (uint)skb);
 #endif
             BufferContext++;
-            dev_kfree_skb (skb);
+            dev_kfree_skb_irq(skb);
         }
-        dev->tbusy = 0;
-
+	netif_wake_queue(dev);
 }
 
 static void
@@ -811,14 +806,8 @@
            (uint)pDpa, (uint)dev, (uint)pDpa->id);
     printk("dev = 0x%x\n", (uint)dev);
 #endif
-    if (dev->interrupt)
-        printk("%s: Re-entering the interrupt handler.\n", dev->name);
-    dev->interrupt = 1;
 
     RCProcI2OMsgQ(pDpa->id);
-    dev->interrupt = 0;
-
-    return;
 }
 
 
@@ -870,7 +859,7 @@
                        (uint)pDpa->numOutRcvBuffers);
             }
             printk("rc: Initialization done.\n");
-            dev->tbusy=0;
+            netif_wake_queue(dev);
             retry=0;
             return;
         case RC_RTN_FREE_Q_EMPTY:
@@ -913,6 +902,8 @@
 
     PDPA pDpa = (PDPA) dev->priv;
 
+    netif_stop_queue(dev);
+    
 #ifdef RCDEBUG
     printk("rc: RCclose\r\n");
 #endif
diff -u --recursive --new-file v2.3.44/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c
--- v2.3.44/linux/drivers/net/rtl8129.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/rtl8129.c	Sun Feb 13 18:24:53 2000
@@ -0,0 +1,1467 @@
+/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */
+/*
+	Written 1997-1999 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+    All other rights reserved.
+
+	This driver is for boards based on the RTL8129 PCI ethernet chip.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
+
+	Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
+*/
+
+static const char *version =
+"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+
+/* A few user-configurable values. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+#define rtl8129_debug debug
+static int rtl8129_debug = 1;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* Used to pass the full-duplex flag, etc. */
+#define MAX_UNITS 8		/* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX	3			/* 0==8K, 1==16K, 2==32K, 3==64K */
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE	1536
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
+#define RX_FIFO_THRESH	4		/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	4		/* Maximum PCI burst, '4' is 256 bytes */
+#define TX_DMA_BURST	4		/* Calculate as 16<<val. */
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
+   This is only in the support-all-kernels source code. */
+
+#define RUN_AT(x) (jiffies + (x))
+
+#include <linux/delay.h>
+
+#if LINUX_VERSION_CODE < 0x20123
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#endif
+#if LINUX_VERSION_CODE <= 0x20139
+#define	net_device_stats enet_statistics
+#else
+#define NETSTATS_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
+/* Grrrr, the PCI code changed, but did not consider CardBus... */
+#include <linux/bios32.h>
+#define PCI_SUPPORT_VER1
+#else
+#define PCI_SUPPORT_VER2
+#endif
+
+/* The I/O extent. */
+#define RTL8129_TOTAL_SIZE 0x80
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the RealTek RTL8129, the RealTek Fast
+Ethernet controllers for PCI.  This chip is used on a few clone boards.
+
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Rx Ring buffers
+
+The receive unit uses a single linear ring buffer rather than the more
+common (and more efficient) descriptor-based architecture.  Incoming frames
+are sequentially stored into the Rx region, and the host copies them into
+skbuffs.
+
+Comment: While it is theoretically possible to process many frames in place,
+any delay in Rx processing would cause us to drop frames.  More importantly,
+the Linux protocol stack is not designed to operate in this manner.
+
+IIIb. Tx operation
+
+The RTL8129 uses a fixed set of four Tx descriptors in register space.
+In a stunningly bad design choice, Tx frames must be 32 bit aligned.  Linux
+aligns the IP header on word boundaries, and 14 byte ethernet header means
+that almost all frames will need to be copied to an alignment buffer.
+
+IVb. References
+
+http://www.realtek.com.tw/cn/cn.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+IVc. Errata
+
+*/
+
+
+/* This table drives the PCI probe routines.  It's mostly boilerplate in all
+   of the drivers, and will likely be provided by some future kernel.
+   Note the matching code -- the first table entry matchs all 56** cards but
+   second only the 1234 card.
+*/
+enum pci_flags_bit {
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+struct pci_id_info {
+	const char *name;
+	u16	vendor_id, device_id, device_id_mask, flags;
+	int io_size;
+	struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};
+
+static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
+										  int pci_devfn, long ioaddr,
+										  int irq, int chp_idx, int fnd_cnt);
+
+static struct pci_id_info pci_tbl[] =
+{{ "RealTek RTL8129 Fast Ethernet",
+   0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+#ifdef USE_8139_SUPPORT_ALSO
+ { "RealTek RTL8139 Fast Ethernet",
+   0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+ { "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
+   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+ { "Accton MPX5030 (RealTek RTL8139)",
+   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
+#endif
+ {0,},						/* 0 terminated list. */
+};
+
+/* The capability table matches the chip table above. */
+enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
+static int rtl_cap_tbl[] = {
+	HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
+};
+
+
+/* The rest of these values should never change. */
+#define NUM_TX_DESC	4			/* Number of Tx descriptor registers. */
+
+/* Symbolic offsets to registers. */
+enum RTL8129_registers {
+	MAC0=0,						/* Ethernet hardware address. */
+	MAR0=8,						/* Multicast filter. */
+	TxStatus0=0x10,				/* Transmit status (Four 32bit registers). */
+	TxAddr0=0x20,				/* Tx descriptors (also four 32bit). */
+	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
+	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
+	IntrMask=0x3C, IntrStatus=0x3E,
+	TxConfig=0x40, RxConfig=0x44,
+	Timer=0x48,					/* A general-purpose counter. */
+	RxMissed=0x4C,				/* 24 bits valid, write clears. */
+	Cfg9346=0x50, Config0=0x51, Config1=0x52,
+	FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
+	MultiIntr=0x5C, TxSummary=0x60,
+	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
+	NWayExpansion=0x6A,
+	/* Undocumented registers, but required for proper operation. */
+	FIFOTMS=0x70,	/* FIFO Test Mode Select */
+	CSCR=0x74,	/* Chip Status and Configuration Register. */
+	PARA78=0x78, PARA7c=0x7c,	/* Magic transceiver parameter register. */
+};
+
+enum ChipCmdBits {
+	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+	PCIErr=0x8000, PCSTimeout=0x4000,
+	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
+	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
+};
+enum TxStatusBits {
+	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
+	TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,
+};
+enum RxStatusBits {
+	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
+	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
+	RxBadAlign=0x0002, RxStatusOK=0x0001,
+};
+
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links. */
+enum CSCRBits {
+	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
+	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
+	CSCR_LinkDownCmd=0x0f3c0,
+};
+unsigned long param[4][4]={
+	{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
+	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
+	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
+	{0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
+};
+
+struct ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+};
+
+struct rtl8129_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct net_device *next_module;
+	struct pci_dev *pdev;
+	int chip_id;
+	int chip_revision;
+	unsigned char pci_bus, pci_devfn;
+#if LINUX_VERSION_CODE > 0x20139
+	struct net_device_stats stats;
+#else
+	struct enet_statistics stats;
+#endif
+	struct timer_list timer;	/* Media selection timer. */
+	unsigned int cur_rx;		/* Index into the Rx buffer of next Rx pkt. */
+	unsigned int cur_tx, dirty_tx, tx_flag;
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct ring_info tx_info[NUM_TX_DESC];
+	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
+	unsigned char *rx_ring;
+	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_bufs_dma;
+	char phys[4];						/* MII device addresses. */
+	char twistie, twist_cnt;			/* Twister tune state. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int duplex_lock:1;
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int media2:4;				/* Secondary monitored media port. */
+	unsigned int medialock:1;			/* Don't sense media type. */
+	unsigned int mediasense:1;			/* Media sensing in progress. */
+};
+
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(multicast_filter_limit, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(debug, "i");
+
+static int rtl8129_open(struct net_device *dev);
+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int val);
+static void rtl8129_timer(unsigned long data);
+static void rtl8129_tx_timeout(struct net_device *dev);
+static void rtl8129_init_ring(struct net_device *dev);
+static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int rtl8129_rx(struct net_device *dev);
+static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int rtl8129_close(struct net_device *dev);
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct enet_statistics *rtl8129_get_stats(struct net_device *dev);
+static inline u32 ether_crc(int length, unsigned char *data);
+static void set_rx_mode(struct net_device *dev);
+
+
+/* A list of all installed RTL8129 devices, for removing the driver module. */
+static struct net_device *root_rtl8129_dev = NULL;
+
+/* Ideally we would detect all network cards in slot order.  That would
+   be best done a central PCI probe dispatch, which wouldn't work
+   well when dynamically adding drivers.  So instead we detect just the
+   Rtl81*9 cards in slot order. */
+
+static int __init rtl8129_probe(void)
+{
+	int cards_found = 0;
+	int pci_index = 0;
+	unsigned char pci_bus, pci_device_fn;
+	struct net_device *dev;
+
+	if ( ! pcibios_present())
+		return -ENODEV;
+
+	for (; pci_index < 0xff; pci_index++) {
+		struct pci_dev *pdev;
+		u16 vendor, device, pci_command, new_command;
+		int chip_idx, irq;
+		long ioaddr;
+
+		if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+								&pci_bus, &pci_device_fn)
+			!= PCIBIOS_SUCCESSFUL)
+			break;
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_VENDOR_ID, &vendor);
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_DEVICE_ID, &device);
+
+		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+			if (vendor == pci_tbl[chip_idx].vendor_id
+				&& (device & pci_tbl[chip_idx].device_id_mask) ==
+				pci_tbl[chip_idx].device_id)
+				break;
+		if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
+			continue;
+
+		pdev = pci_find_slot(pci_bus, pci_device_fn);
+		ioaddr = pdev->resource[0].start;
+		irq = pdev->irq;
+
+		if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
+			check_region(ioaddr, pci_tbl[chip_idx].io_size))
+			continue;
+
+		/* Activate the card: fix for brain-damaged Win98 BIOSes. */
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+		new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled the"
+				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_bus, pci_device_fn, pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+									  PCI_COMMAND, new_command);
+		}
+
+		dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found);
+
+		if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
+			u8 pci_latency;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < 32) {
+				printk(KERN_NOTICE "  PCI latency timer (CFLT) is "
+					   "unreasonably low at %d.  Setting to 64 clocks.\n",
+					   pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 64);
+			}
+		}
+		dev = 0;
+		cards_found++;
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
+										 int pci_devfn, long ioaddr,
+										 int irq, int chip_idx, int found_cnt)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct rtl8129_private *tp;
+	int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;
+	struct net_device *dev;
+
+	if (rtl8129_debug > 0  &&  did_version++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	dev = init_etherdev(NULL, 0);
+
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
+		   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
+
+	/* Bring the chip out of low-power mode. */
+	outb(0x00, ioaddr + Config1);
+
+	if (read_eeprom(ioaddr, 0) != 0xffff) {
+		for (i = 0; i < 3; i++) {
+			((u16 *)(dev->dev_addr))[i] =
+				le16_to_cpu(read_eeprom(ioaddr, i + 7));
+		}
+	} else {
+		for (i = 0; i < 6; i++)
+			dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
+	}
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x.\n", dev->dev_addr[i]);
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* Some data structures must be quadword aligned. */
+	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+	memset(tp, 0, sizeof(*tp));
+	dev->priv = tp;
+
+	tp->next_module = root_rtl8129_dev;
+	root_rtl8129_dev = dev;
+
+	tp->pdev = pdev;
+	tp->chip_id = chip_idx;
+	tp->pci_bus = pci_bus;
+	tp->pci_devfn = pci_devfn;
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) {
+		int phy, phy_idx;
+		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+			 phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  && mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
+					   dev->name, phy);
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
+				   "transceiver.\n",
+				   dev->name);
+			tp->phys[0] = -1;
+		}
+	} else
+		tp->phys[0] = 32;
+
+	/* Put the chip into low-power mode. */
+	outb(0xC0, ioaddr + Cfg9346);
+	outb(0x03, ioaddr + Config1);
+	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		tp->full_duplex = (option & 0x200) ? 1 : 0;
+		tp->default_port = option & 15;
+		if (tp->default_port)
+			tp->medialock = 1;
+	}
+
+	if (found_cnt < MAX_UNITS  &&  full_duplex[found_cnt] > 0)
+		tp->full_duplex = full_duplex[found_cnt];
+
+	if (tp->full_duplex) {
+		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+		mdio_write(dev, tp->phys[0], 4, 0x141);
+		tp->duplex_lock = 1;
+	}
+
+	/* The Rtl8129-specific entries in the device structure. */
+	dev->open = &rtl8129_open;
+	dev->hard_start_xmit = &rtl8129_start_xmit;
+	dev->tx_timeout = &rtl8129_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->stop = &rtl8129_close;
+	dev->get_stats = &rtl8129_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &mii_ioctl;
+
+	return dev;
+}
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
+#define EE_CS			0x08	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x00
+#define EE_WRITE_1		0x02
+#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
+#define EE_ENB			(0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay()	inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+static int read_eeprom(long ioaddr, int location)
+{
+	int i;
+	unsigned retval = 0;
+	long ee_addr = ioaddr + Cfg9346;
+	int read_cmd = location | EE_READ_CMD;
+
+	outb(EE_ENB & ~EE_CS, ee_addr);
+	outb(EE_ENB, ee_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outb(EE_ENB | dataval, ee_addr);
+		eeprom_delay();
+		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+	}
+	outb(EE_ENB, ee_addr);
+	eeprom_delay();
+
+	for (i = 16; i > 0; i--) {
+		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outb(EE_ENB, ee_addr);
+		eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	outb(~EE_CS, ee_addr);
+	return retval;
+}
+
+/* MII serial management: mostly bogus for now. */
+/* Read and write the MII management registers using software-generated
+   serial MDIO protocol.
+   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues. */
+#define MDIO_DIR		0x80
+#define MDIO_DATA_OUT	0x04
+#define MDIO_DATA_IN	0x02
+#define MDIO_CLK		0x01
+#define MDIO_WRITE0 (MDIO_DIR)
+#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
+
+#define mdio_delay()	inb(mdio_addr)
+
+static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,
+								 NWayLPAR, NWayExpansion, 0 };
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync(long mdio_addr)
+{
+	int i;
+
+	for (i = 32; i >= 0; i--) {
+		outb(MDIO_WRITE1, mdio_addr);
+		mdio_delay();
+		outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	long mdio_addr = dev->base_addr + MII_SMI;
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int retval = 0;
+	int i;
+
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		return location < 8 && mii_2_8139_map[location] ?
+			inw(dev->base_addr + mii_2_8139_map[location]) : 0;
+	}
+	mdio_sync(mdio_addr);
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
+
+		outb(MDIO_DIR | dataval, mdio_addr);
+		mdio_delay();
+		outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outb(0, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
+		outb(MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	long mdio_addr = dev->base_addr + MII_SMI;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	int i;
+
+	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
+		if (location < 8  &&  mii_2_8139_map[location])
+			outw(value, dev->base_addr + mii_2_8139_map[location]);
+		return;
+	}
+	mdio_sync(mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+		outb(dataval, mdio_addr);
+		mdio_delay();
+		outb(dataval | MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		outb(0, mdio_addr);
+		mdio_delay();
+		outb(MDIO_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+
+
+static int
+rtl8129_open(struct net_device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	/* Soft reset the chip. */
+	outb(CmdReset, ioaddr + ChipCmd);
+
+	if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
+		return -EAGAIN;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	tp->tx_bufs = pci_alloc_consistent(tp->pdev,
+									   TX_BUF_SIZE * NUM_TX_DESC,
+									   &tp->tx_bufs_dma);
+	tp->rx_ring = pci_alloc_consistent(tp->pdev,
+									   RX_BUF_LEN + 16,
+									   &tp->rx_ring_dma);
+	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {
+		free_irq(dev->irq, dev);
+		if (tp->tx_bufs)
+			pci_free_consistent(tp->pdev,
+								TX_BUF_SIZE * NUM_TX_DESC,
+								tp->tx_bufs, tp->tx_bufs_dma);
+		if (tp->rx_ring)
+			pci_free_consistent(tp->pdev,
+								RX_BUF_LEN + 16,
+								tp->rx_ring, tp->rx_ring_dma);
+		if (rtl8129_debug > 0)
+			printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
+				   dev->name, RX_BUF_LEN);
+		return -ENOMEM;
+	}
+	rtl8129_init_ring(dev);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
+			break;
+
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
+		 ioaddr + RxConfig);
+	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
+	tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
+
+	tp->full_duplex = tp->duplex_lock;
+	if (tp->phys[0] >= 0  ||  (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) {
+		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+		if (mii_reg5 == 0xffff)
+			;					/* Not there */
+		else if ((mii_reg5 & 0x0100) == 0x0100
+				 || (mii_reg5 & 0x00C0) == 0x0040)
+			tp->full_duplex = 1;
+		if (rtl8129_debug > 1)
+			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+				   " auto-negotiated partner ability %4.4x.\n", dev->name,
+				   mii_reg5 == 0 ? "" :
+				   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
+				   tp->full_duplex ? "full" : "half", mii_reg5);
+	}
+
+	outb(0xC0, ioaddr + Cfg9346);
+	outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+	outb(0x00, ioaddr + Cfg9346);
+
+	outl(tp->rx_ring_dma, ioaddr + RxBuf);
+
+	/* Start the chip's Tx and Rx process. */
+	outl(0, ioaddr + RxMissed);
+	set_rx_mode(dev);
+
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+
+	/* Enable all known interrupts by setting the interrupt mask. */
+	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+
+	if (rtl8129_debug > 1)
+		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
+			   " GP Pins %2.2x %s-duplex.\n",
+			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
+			   tp->full_duplex ? "full" : "half");
+
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&tp->timer);
+	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = &rtl8129_timer;
+	add_timer(&tp->timer);
+
+	return 0;
+}
+
+static void rtl8129_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+	int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+
+	if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {
+		int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+		if (tp->full_duplex != duplex) {
+			tp->full_duplex = duplex;
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
+				   " partner ability of %4.4x.\n", dev->name,
+				   tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);
+			outb(0xC0, ioaddr + Cfg9346);
+			outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+			outb(0x00, ioaddr + Cfg9346);
+		}
+	}
+	/* Check for bogusness. */
+	if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
+		int status = inw(ioaddr + IntrStatus);
+		if (status & (TxOK | RxOK)) {	/* Double check */
+			printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n",
+				   dev->name, status);
+			rtl8129_interrupt(dev->irq, dev, 0);
+		}
+	}
+	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
+		(jiffies - dev->trans_start) >= 2*TX_TIMEOUT)
+		rtl8129_tx_timeout(dev);
+
+#if 0
+	if (tp->twistie) {
+		unsigned int CSCRval = inw(ioaddr + CSCR);		/* Read link status. */
+		if (tp->twistie == 1) {
+			if (CSCRval & CSCR_LinkOKBit) {
+				outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
+				tp->twistie = 2;
+				next_tick = HZ/10;
+			} else {
+				outw(CSCR_LinkDownCmd, ioaddr + CSCR);
+				outl(FIFOTMS_default,ioaddr + FIFOTMS);
+				outl(PARA78_default ,ioaddr + PARA78);
+				outl(PARA7c_default ,ioaddr + PARA7c);
+				tp->twistie = 0;
+			}
+		} else if (tp->twistie == 2) {
+			int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12;
+			int row;
+			if (linkcase >= 0x7000) row = 3;
+			else if (linkcase >= 0x3000) row = 2;
+			else if (linkcase >= 0x1000) row = 1;
+			else row = 0;
+			tp->twistie == row + 3;
+			outw(0,ioaddr+FIFOTMS);
+			outl(param[row][0], ioaddr+PARA7c);
+			tp->twist_cnt = 1;
+		} else {
+			outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c);
+			if (++tp->twist_cnt < 4) {
+				next_tick = HZ/10;
+			} else if (tp->twistie-3 == 3) {
+				if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) {
+					outl(PARA7c_xxx, ioaddr+PARA7c);
+					next_tick = HZ/10; 		/* 100ms. */
+					outl(FIFOTMS_default, ioaddr+FIFOTMS);
+					outl(PARA78_default,  ioaddr+PARA78);
+					outl(PARA7c_default,  ioaddr+PARA7c);
+					tp->twistie == 3 + 3;
+					outw(0,ioaddr+FIFOTMS);
+					outl(param[3][0], ioaddr+PARA7c);
+					tp->twist_cnt = 1;
+				}
+			}
+		}
+	}
+#endif
+
+	if (rtl8129_debug > 2) {
+		if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
+			printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
+				   dev->name, inb(ioaddr + GPPinData));
+		else
+			printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
+				   dev->name, inw(ioaddr + NWayLPAR));
+		printk(KERN_DEBUG"%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
+			   " RxStatus %4.4x.\n",
+			   dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
+			   inl(ioaddr + RxEarlyStatus));
+		printk(KERN_DEBUG"%s:  Chip config %2.2x %2.2x.\n",
+			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
+	}
+
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void rtl8129_tx_timeout(struct net_device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int mii_reg, i;
+
+	if (rtl8129_debug > 0)
+		printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x "
+			   "media %2.2x.\n",
+			   dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),
+			   inb(ioaddr + GPPinData));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outw(0x0000, ioaddr + IntrMask);
+	/* Emit info to figure out what went wrong. */
+	printk("%s: Tx queue start entry %d  dirty entry %d.\n",
+		   dev->name, tp->cur_tx, tp->dirty_tx);
+	for (i = 0; i < NUM_TX_DESC; i++)
+		printk(KERN_DEBUG"%s:  Tx descriptor %d is %8.8x.%s\n",
+			   dev->name, i, inl(ioaddr + TxStatus0 + i*4),
+			   i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
+	printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
+	for (mii_reg = 0; mii_reg < 8; mii_reg++)
+		printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));
+	printk(".\n");
+
+	/* Soft reset the chip. */
+	outb(CmdReset, ioaddr + ChipCmd);
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--)
+		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
+			break;
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
+
+	outb(0x00, ioaddr + Cfg9346);
+	tp->cur_rx = 0;
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
+		 ioaddr + RxConfig);
+	outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
+	set_rx_mode(dev);
+	{							/* Save the unsent Tx packets. */
+		struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
+		int j;
+		for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) {
+			struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC];
+
+			saved_skb[j] = rp->skb;
+			if (rp->mapping != 0) {
+				pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len);
+				rp->mapping = 0;
+			}
+		}
+		tp->dirty_tx = tp->cur_tx = 0;
+
+		for (i = 0; i < j; i++) {
+			skb = tp->tx_info[i].skb = saved_skb[i];
+			if ((long)skb->data & 3) {		/* Must use alignment buffer. */
+				memcpy(tp->tx_buf[i], skb->data, skb->len);
+				outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs),
+					 ioaddr + TxAddr0 + i*4);
+			} else {
+				tp->tx_info[i].mapping =
+					pci_map_single(tp->pdev, skb->data, skb->len);
+				outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);
+			}
+			/* Note: the chip doesn't have auto-pad! */
+			outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+				 ioaddr + TxStatus0 + i*4);
+		}
+		tp->cur_tx = i;
+		while (i < NUM_TX_DESC) {
+			tp->tx_info[i].skb = NULL;
+			tp->tx_info[i].mapping = 0;
+			i++;
+		}
+		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
+			netif_wake_queue(dev);
+			tp->tx_full = 0;
+		} else {
+			tp->tx_full = 1;
+			netif_stop_queue(dev);
+		}
+	}
+
+	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
+	/* Enable all known interrupts by setting the interrupt mask. */
+	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
+	return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+rtl8129_init_ring(struct net_device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int i;
+
+	tp->tx_full = 0;
+	tp->cur_rx = 0;
+	tp->dirty_tx = tp->cur_tx = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
+		tp->tx_info[i].skb = NULL;
+		tp->tx_info[i].mapping = 0;
+	}
+}
+
+static int
+rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int entry;
+
+	netif_stop_queue(dev);
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % NUM_TX_DESC;
+
+	tp->tx_info[entry].skb = skb;
+	if ((long)skb->data & 3) {			/* Must use alignment buffer. */
+		tp->tx_info[entry].mapping = 0;
+		memcpy(tp->tx_buf[entry], skb->data, skb->len);
+		outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs),
+			 ioaddr + TxAddr0 + entry*4);
+	} else {
+		tp->tx_info[entry].mapping =
+			pci_map_single(tp->pdev, skb->data, skb->len);
+		outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4);
+	}
+	/* Note: the chip doesn't have auto-pad! */
+	outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
+		 ioaddr + TxStatus0 + entry*4);
+
+	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {	/* Typical path */
+		netif_start_queue(dev);
+	} else {
+		tp->tx_full = 1;
+	}
+
+	dev->trans_start = jiffies;
+	if (rtl8129_debug > 4)
+		printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
+			   dev->name, skb->data, (int)skb->len, entry);
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int boguscnt = max_interrupt_work;
+	int status, link_changed = 0;
+	long ioaddr = dev->base_addr;
+
+	do {
+		status = inw(ioaddr + IntrStatus);
+		/* Acknowledge all of the current interrupt sources ASAP, but
+		   an first get an additional status bit from CSCR. */
+		if ((status & RxUnderrun)  &&  inw(ioaddr+CSCR) & CSCR_LinkChangeBit)
+			link_changed = 1;
+		outw(status, ioaddr + IntrStatus);
+
+		if (rtl8129_debug > 4)
+			printk(KERN_DEBUG"%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
+				   dev->name, status, inw(ioaddr + IntrStatus));
+
+		if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver
+					   |TxErr|TxOK|RxErr|RxOK)) == 0)
+			break;
+
+		if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */
+			rtl8129_rx(dev);
+
+		if (status & (TxOK | TxErr)) {
+			unsigned int dirty_tx = tp->dirty_tx;
+
+			while (tp->cur_tx - dirty_tx > 0) {
+				int entry = dirty_tx % NUM_TX_DESC;
+				int txstatus = inl(ioaddr + TxStatus0 + entry*4);
+
+				if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+					break;			/* It still hasn't been Txed */
+
+				/* Note: TxCarrierLost is always asserted at 100mbps. */
+				if (txstatus & (TxOutOfWindow | TxAborted)) {
+					/* There was an major error, log it. */
+					if (rtl8129_debug > 1)
+						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, txstatus);
+					tp->stats.tx_errors++;
+					if (txstatus&TxAborted) {
+						tp->stats.tx_aborted_errors++;
+						outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);
+					}
+					if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;
+					if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;
+#ifdef ETHER_STATS
+					if ((txstatus & 0x0f000000) == 0x0f000000)
+						tp->stats.collisions16++;
+#endif
+				} else {
+					if (txstatus & TxUnderrun) {
+						/* Add 64 to the Tx FIFO threshold. */
+						if (tp->tx_flag <  0x00300000)
+							tp->tx_flag += 0x00020000;
+						tp->stats.tx_fifo_errors++;
+					}
+					tp->stats.collisions += (txstatus >> 24) & 15;
+#if LINUX_VERSION_CODE > 0x20119
+					tp->stats.tx_bytes += txstatus & 0x7ff;
+#endif
+					tp->stats.tx_packets++;
+				}
+
+				if (tp->tx_info[entry].mapping != 0) {
+					pci_unmap_single(tp->pdev,
+									 tp->tx_info[entry].mapping,
+									 tp->tx_info[entry].skb->len);
+					tp->tx_info[entry].mapping = 0;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb_irq(tp->tx_info[entry].skb);
+				tp->tx_info[entry].skb = NULL;
+				if (tp->tx_full) {
+					/* The ring is no longer full, wake the queue. */
+					tp->tx_full = 0;
+					netif_wake_queue(dev);
+				}
+				dirty_tx++;
+			}
+
+#ifndef final_version
+			if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+				printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+				dirty_tx += NUM_TX_DESC;
+			}
+#endif
+			tp->dirty_tx = dirty_tx;
+		}
+
+		/* Check uncommon events with one test. */
+		if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
+					  |TxErr|RxErr)) {
+			if (rtl8129_debug > 2)
+				printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",
+					   dev->name, status);
+
+			if (status == 0xffffffff)
+				break;
+			/* Update the error count. */
+			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+			outl(0, ioaddr + RxMissed);
+
+			if ((status & RxUnderrun)  &&  link_changed  &&
+				(rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) {
+				/* Really link-change on new chips. */
+				int lpar = inw(ioaddr + NWayLPAR);
+				int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; 
+				if (tp->full_duplex != duplex) {
+					tp->full_duplex = duplex;
+					outb(0xC0, ioaddr + Cfg9346);
+					outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
+					outb(0x00, ioaddr + Cfg9346);
+				}
+				status &= ~RxUnderrun;
+			}
+			if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
+				tp->stats.rx_errors++;
+
+			if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
+			if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;
+			if (status & RxOverflow) {
+				tp->stats.rx_over_errors++;
+				tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
+				outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
+			}
+			if (status & PCIErr) {
+				u32 pci_cmd_status;
+				pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn,
+										  PCI_COMMAND, &pci_cmd_status);
+
+				printk(KERN_ERR "%s: PCI Bus error %4.4x.\n",
+					   dev->name, pci_cmd_status);
+			}
+		}
+		if (--boguscnt < 0) {
+			printk(KERN_WARNING"%s: Too much work at interrupt, "
+				   "IntrStatus=0x%4.4x.\n",
+				   dev->name, status);
+			/* Clear all interrupt sources. */
+			outw(0xffff, ioaddr + IntrStatus);
+			break;
+		}
+	} while (1);
+
+	if (rtl8129_debug > 3)
+		printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
+			   dev->name, inl(ioaddr + IntrStatus));
+	return;
+}
+
+/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
+   field alignments and semantics. */
+static int rtl8129_rx(struct net_device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	unsigned char *rx_ring = tp->rx_ring;
+	u16 cur_rx = tp->cur_rx;
+
+	if (rtl8129_debug > 4)
+		printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"
+			   " free to %4.4x, Cmd %2.2x.\n",
+			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
+			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
+
+	while ((inb(ioaddr + ChipCmd) & 1) == 0) {
+		int ring_offset = cur_rx % RX_BUF_LEN;
+		u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset));
+		int rx_size = rx_status >> 16;
+
+		if (rtl8129_debug > 4) {
+			int i;
+			printk(KERN_DEBUG"%s:  rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",
+				   dev->name, rx_status, rx_size, cur_rx);
+			printk(KERN_DEBUG"%s: Frame contents ", dev->name);
+			for (i = 0; i < 70; i++)
+				printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i]));
+			printk(".\n");
+		}
+		if (rx_status & RxTooLong) {
+			if (rtl8129_debug > 0)
+				printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",
+					   dev->name, rx_status);
+			tp->stats.rx_length_errors++;
+		} else if (rx_status &
+				   (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
+			if (rtl8129_debug > 1)
+				printk(KERN_DEBUG"%s: Ethernet frame had errors,"
+					   " status %4.4x.\n", dev->name, rx_status);
+			tp->stats.rx_errors++;
+			if (rx_status & (RxBadSymbol|RxBadAlign))
+				tp->stats.rx_frame_errors++;
+			if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;
+			if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
+			/* Reset the receiver, based on RealTek recommendation. (Bug?) */
+			tp->cur_rx = 0;
+			outb(CmdTxEnb, ioaddr + ChipCmd);
+			outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
+			outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |
+				 (RX_DMA_BURST<<8), ioaddr + RxConfig);
+		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
+			/* Omit the four octet CRC from the length. */
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(rx_size + 2);
+			if (skb == NULL) {
+				printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",
+					   dev->name);
+				/* We should check that some rx space is free.
+				   If not, free one and mark stats->rx_dropped++. */
+				tp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */
+			if (ring_offset+rx_size+4 > RX_BUF_LEN) {
+				int semi_count = RX_BUF_LEN - ring_offset - 4;
+				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
+					   semi_count);
+				memcpy(skb_put(skb, rx_size-semi_count), rx_ring,
+					   rx_size-semi_count);
+				if (rtl8129_debug > 4) {
+					int i;
+					printk(KERN_DEBUG"%s:  Frame wrap @%d",
+						   dev->name, semi_count);
+					for (i = 0; i < 16; i++)
+						printk(" %2.2x", le32_to_cpu(rx_ring[i]));
+					printk(".\n");
+					memset(rx_ring, 0xcc, 16);
+				}
+			} else {
+#if 1  /* USE_IP_COPYSUM */
+				eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],
+								 rx_size, 0);
+				skb_put(skb, rx_size);
+#else
+				memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
+					   rx_size);
+#endif
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+#if LINUX_VERSION_CODE > 0x20119
+			tp->stats.rx_bytes += rx_size;
+#endif
+			tp->stats.rx_packets++;
+		}
+
+		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+		outw(cur_rx - 16, ioaddr + RxBufPtr);
+	}
+	if (rtl8129_debug > 4)
+		printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"
+			   " free to %4.4x, Cmd %2.2x.\n",
+			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
+			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
+	tp->cur_rx = cur_rx;
+	return 0;
+}
+
+static int
+rtl8129_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	int i;
+
+	netif_stop_queue(dev);
+
+	if (rtl8129_debug > 1)
+		printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
+			   dev->name, inw(ioaddr + IntrStatus));
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outw(0x0000, ioaddr + IntrMask);
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	outb(0x00, ioaddr + ChipCmd);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+	outl(0, ioaddr + RxMissed);
+
+	del_timer(&tp->timer);
+
+	free_irq(dev->irq, dev);
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		struct sk_buff *skb = tp->tx_info[i].skb;
+		dma_addr_t mapping = tp->tx_info[i].mapping;
+
+		if (skb) {
+			if (mapping)
+				pci_unmap_single(tp->pdev, mapping, skb->len);
+			dev_kfree_skb(skb);
+		}
+		tp->tx_info[i].skb = NULL;
+		tp->tx_info[i].mapping = 0;
+	}
+	pci_free_consistent(tp->pdev, RX_BUF_LEN + 16,
+						tp->rx_ring, tp->rx_ring_dma);
+	pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC,
+						tp->tx_bufs, tp->tx_bufs_dma);
+	tp->rx_ring = NULL;
+	tp->tx_bufs = NULL;
+
+	/* Green! Put the chip in low-power mode. */
+	outb(0xC0, ioaddr + Cfg9346);
+	outb(0x03, ioaddr + Config1);
+	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = tp->phys[0] & 0x3f;
+		/* Fall Through */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		data[3] = mdio_read(dev, data[0], data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static struct enet_statistics *
+rtl8129_get_stats(struct net_device *dev)
+{
+	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (test_bit(LINK_STATE_START, &dev->state)) {
+		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
+		outl(0, ioaddr + RxMissed);
+	}
+
+	return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   This routine is not state sensitive and need not be SMP locked. */
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+    int crc = -1;
+
+    while (--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^
+				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+    }
+    return crc;
+}
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
+	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
+};
+
+static void set_rx_mode(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	u32 mc_filter[2];		 /* Multicast hash filter */
+	int i, rx_mode;
+
+	if (rtl8129_debug > 3)
+		printk(KERN_DEBUG"%s:   set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+			   dev->name, dev->flags, inl(ioaddr + RxConfig));
+
+	/* Note: do not reorder, GCC is clever about common statements. */
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
+		rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else if ((dev->mc_count > multicast_filter_limit)
+			   ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else {
+		struct dev_mc_list *mclist;
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next)
+			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
+	}
+	/* We can safely update without stopping the chip. */
+	outb(rx_mode, ioaddr + RxConfig);
+	outl(mc_filter[0], ioaddr + MAR0 + 0);
+	outl(mc_filter[1], ioaddr + MAR0 + 4);
+	return;
+}
+
+
+static void __exit rtl8129_cleanup (void)
+{
+	struct net_device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_rtl8129_dev) {
+		struct rtl8129_private *tp =
+			(struct rtl8129_private *)root_rtl8129_dev->priv;
+		next_dev = tp->next_module;
+		unregister_netdev(root_rtl8129_dev);
+		release_region(root_rtl8129_dev->base_addr,
+					   pci_tbl[tp->chip_id].io_size);
+		kfree(tp);
+		kfree(root_rtl8129_dev);
+		root_rtl8129_dev = next_dev;
+	}
+}
+
+module_init(rtl8129_probe);
+module_exit(rtl8129_cleanup);
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.3.44/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.3.44/linux/drivers/net/rtl8139.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/rtl8139.c	Wed Dec 31 16:00:00 1969
@@ -1,1473 +0,0 @@
-/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
-/*
-	Written 1997-1999 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU Public License, incorporated herein by reference.
-    All other rights reserved.
-
-	This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
-	chips.
-
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
-	Support and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
-
-	Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
-*/
-
-static const char *version =
-"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
-
-/* A few user-configurable values. */
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-#define rtl8129_debug debug
-static int rtl8129_debug = 1;
-
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
-   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
-static int multicast_filter_limit = 32;
-
-/* Used to pass the full-duplex flag, etc. */
-#define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Size of the in-memory receive ring. */
-#define RX_BUF_LEN_IDX	3			/* 0==8K, 1==16K, 2==32K, 3==64K */
-#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
-/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
-#define TX_BUF_SIZE	1536
-
-/* PCI Tuning Parameters
-   Threshold is bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
-
-/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
-#define RX_FIFO_THRESH	4		/* Rx buffer level before first PCI xfer.  */
-#define RX_DMA_BURST	4		/* Maximum PCI burst, '4' is 256 bytes */
-#define TX_DMA_BURST	4		/* Calculate as 16<<val. */
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (4*HZ)
-
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#include <linux/delay.h>
-
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define	net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-
-/* The I/O extent. */
-#define RTL8129_TOTAL_SIZE 0x80
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the RealTek RTL8129, the RealTek Fast
-Ethernet controllers for PCI.  This chip is used on a few clone boards.
-
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS will assign the
-PCI INTA signal to a (preferably otherwise unused) system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
-
-III. Driver operation
-
-IIIa. Rx Ring buffers
-
-The receive unit uses a single linear ring buffer rather than the more
-common (and more efficient) descriptor-based architecture.  Incoming frames
-are sequentially stored into the Rx region, and the host copies them into
-skbuffs.
-
-Comment: While it is theoretically possible to process many frames in place,
-any delay in Rx processing would cause us to drop frames.  More importantly,
-the Linux protocol stack is not designed to operate in this manner.
-
-IIIb. Tx operation
-
-The RTL8129 uses a fixed set of four Tx descriptors in register space.
-In a stunningly bad design choice, Tx frames must be 32 bit aligned.  Linux
-aligns the IP header on word boundaries, and 14 byte ethernet header means
-that almost all frames will need to be copied to an alignment buffer.
-
-IVb. References
-
-http://www.realtek.com.tw/cn/cn.html
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-
-IVc. Errata
-
-*/
-
-
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-   Note the matching code -- the first table entry matchs all 56** cards but
-   second only the 1234 card.
-*/
-enum pci_flags_bit {
-	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-struct pci_id_info {
-	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
-	int io_size;
-	struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
-										  int pci_devfn, long ioaddr,
-										  int irq, int chp_idx, int fnd_cnt);
-
-static struct pci_id_info pci_tbl[] =
-{{ "RealTek RTL8129 Fast Ethernet",
-   0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "RealTek RTL8139 Fast Ethernet",
-   0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
-   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "Accton MPX5030 (RealTek RTL8139)",
-   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- {0,},						/* 0 terminated list. */
-};
-
-/* The capability table matches the chip table above. */
-enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
-static int rtl_cap_tbl[] = {
-	HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
-};
-
-
-/* The rest of these values should never change. */
-#define NUM_TX_DESC	4			/* Number of Tx descriptor registers. */
-
-/* Symbolic offsets to registers. */
-enum RTL8129_registers {
-	MAC0=0,						/* Ethernet hardware address. */
-	MAR0=8,						/* Multicast filter. */
-	TxStatus0=0x10,				/* Transmit status (Four 32bit registers). */
-	TxAddr0=0x20,				/* Tx descriptors (also four 32bit). */
-	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
-	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
-	IntrMask=0x3C, IntrStatus=0x3E,
-	TxConfig=0x40, RxConfig=0x44,
-	Timer=0x48,					/* A general-purpose counter. */
-	RxMissed=0x4C,				/* 24 bits valid, write clears. */
-	Cfg9346=0x50, Config0=0x51, Config1=0x52,
-	FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
-	MultiIntr=0x5C, TxSummary=0x60,
-	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
-	NWayExpansion=0x6A,
-	/* Undocumented registers, but required for proper operation. */
-	FIFOTMS=0x70,	/* FIFO Test Mode Select */
-	CSCR=0x74,	/* Chip Status and Configuration Register. */
-	PARA78=0x78, PARA7c=0x7c,	/* Magic transceiver parameter register. */
-};
-
-enum ChipCmdBits {
-	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
-	PCIErr=0x8000, PCSTimeout=0x4000,
-	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
-	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
-};
-enum TxStatusBits {
-	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
-	TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,
-};
-enum RxStatusBits {
-	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
-	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
-	RxBadAlign=0x0002, RxStatusOK=0x0001,
-};
-
-/* Twister tuning parameters from RealTek.
-   Completely undocumented, but required to tune bad links. */
-enum CSCRBits {
-	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
-	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
-	CSCR_LinkDownCmd=0x0f3c0,
-};
-unsigned long param[4][4]={
-	{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
-	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
-	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
-	{0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
-};
-
-struct ring_info {
-	struct sk_buff *skb;
-	dma_addr_t mapping;
-};
-
-struct rtl8129_private {
-	char devname[8];			/* Used only for kernel debugging. */
-	const char *product_name;
-	struct net_device *next_module;
-	struct pci_dev *pdev;
-	int chip_id;
-	int chip_revision;
-	unsigned char pci_bus, pci_devfn;
-#if LINUX_VERSION_CODE > 0x20139
-	struct net_device_stats stats;
-#else
-	struct enet_statistics stats;
-#endif
-	struct timer_list timer;	/* Media selection timer. */
-	unsigned int cur_rx;		/* Index into the Rx buffer of next Rx pkt. */
-	unsigned int cur_tx, dirty_tx, tx_flag;
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	struct ring_info tx_info[NUM_TX_DESC];
-	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
-	unsigned char *rx_ring;
-	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
-	dma_addr_t rx_ring_dma;
-	dma_addr_t tx_bufs_dma;
-	char phys[4];						/* MII device addresses. */
-	char twistie, twist_cnt;			/* Twister tune state. */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int duplex_lock:1;
-	unsigned int default_port:4;		/* Last dev->if_port value. */
-	unsigned int media2:4;				/* Secondary monitored media port. */
-	unsigned int medialock:1;			/* Don't sense media type. */
-	unsigned int mediasense:1;			/* Media sensing in progress. */
-};
-
-#ifdef MODULE
-#if LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(multicast_filter_limit, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(debug, "i");
-#endif
-#endif
-
-static int rtl8129_open(struct net_device *dev);
-static int read_eeprom(long ioaddr, int location);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int location, int val);
-static void rtl8129_timer(unsigned long data);
-static void rtl8129_tx_timeout(struct net_device *dev);
-static void rtl8129_init_ring(struct net_device *dev);
-static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int rtl8129_rx(struct net_device *dev);
-static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int rtl8129_close(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct enet_statistics *rtl8129_get_stats(struct net_device *dev);
-static inline u32 ether_crc(int length, unsigned char *data);
-static void set_rx_mode(struct net_device *dev);
-
-
-/* A list of all installed RTL8129 devices, for removing the driver module. */
-static struct net_device *root_rtl8129_dev = NULL;
-
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   Rtl81*9 cards in slot order. */
-
-int rtl8139_probe(void)
-{
-	int cards_found = 0;
-	int pci_index = 0;
-	unsigned char pci_bus, pci_device_fn;
-	struct net_device *dev;
-
-	if ( ! pcibios_present())
-		return -ENODEV;
-
-	for (; pci_index < 0xff; pci_index++) {
-		struct pci_dev *pdev;
-		u16 vendor, device, pci_command, new_command;
-		int chip_idx, irq;
-		long ioaddr;
-
-		if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-								&pci_bus, &pci_device_fn)
-			!= PCIBIOS_SUCCESSFUL)
-			break;
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_VENDOR_ID, &vendor);
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_DEVICE_ID, &device);
-
-		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-			if (vendor == pci_tbl[chip_idx].vendor_id
-				&& (device & pci_tbl[chip_idx].device_id_mask) ==
-				pci_tbl[chip_idx].device_id)
-				break;
-		if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
-			continue;
-
-		pdev = pci_find_slot(pci_bus, pci_device_fn);
-		ioaddr = pdev->resource[0].start;
-		irq = pdev->irq;
-
-		if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
-			check_region(ioaddr, pci_tbl[chip_idx].io_size))
-			continue;
-
-		/* Activate the card: fix for brain-damaged Win98 BIOSes. */
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_COMMAND, &pci_command);
-		new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled the"
-				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_bus, pci_device_fn, pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-									  PCI_COMMAND, new_command);
-		}
-
-		dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found);
-
-		if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-			u8 pci_latency;
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < 32) {
-				printk(KERN_NOTICE "  PCI latency timer (CFLT) is "
-					   "unreasonably low at %d.  Setting to 64 clocks.\n",
-					   pci_latency);
-				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										  PCI_LATENCY_TIMER, 64);
-			}
-		}
-		dev = 0;
-		cards_found++;
-	}
-
-	return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
-										 int pci_devfn, long ioaddr,
-										 int irq, int chip_idx, int found_cnt)
-{
-	static int did_version = 0;			/* Already printed version info. */
-	struct rtl8129_private *tp;
-	int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;
-	struct net_device *dev;
-
-	if (rtl8129_debug > 0  &&  did_version++ == 0)
-		printk(KERN_INFO "%s", version);
-
-	dev = init_etherdev(NULL, 0);
-
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-		   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
-
-	/* Bring the chip out of low-power mode. */
-	outb(0x00, ioaddr + Config1);
-
-	if (read_eeprom(ioaddr, 0) != 0xffff) {
-		for (i = 0; i < 3; i++) {
-			((u16 *)(dev->dev_addr))[i] =
-				le16_to_cpu(read_eeprom(ioaddr, i + 7));
-		}
-	} else {
-		for (i = 0; i < 6; i++)
-			dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
-	}
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x.\n", dev->dev_addr[i]);
-
-	/* We do a request_region() to register /proc/ioports info. */
-	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	/* Some data structures must be quadword aligned. */
-	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
-	memset(tp, 0, sizeof(*tp));
-	dev->priv = tp;
-
-	tp->next_module = root_rtl8129_dev;
-	root_rtl8129_dev = dev;
-
-	tp->pdev = pdev;
-	tp->chip_id = chip_idx;
-	tp->pci_bus = pci_bus;
-	tp->pci_devfn = pci_devfn;
-
-	/* Find the connected MII xcvrs.
-	   Doing this in open() would allow detecting external xcvrs later, but
-	   takes too much time. */
-	if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) {
-		int phy, phy_idx;
-		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
-			 phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
-			if (mii_status != 0xffff  && mii_status != 0x0000) {
-				tp->phys[phy_idx++] = phy;
-				printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
-					   dev->name, phy);
-			}
-		}
-		if (phy_idx == 0) {
-			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
-				   "transceiver.\n",
-				   dev->name);
-			tp->phys[0] = -1;
-		}
-	} else
-		tp->phys[0] = 32;
-
-	/* Put the chip into low-power mode. */
-	outb(0xC0, ioaddr + Cfg9346);
-	outb(0x03, ioaddr + Config1);
-	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
-
-	/* The lower four bits are the media type. */
-	if (option > 0) {
-		tp->full_duplex = (option & 0x200) ? 1 : 0;
-		tp->default_port = option & 15;
-		if (tp->default_port)
-			tp->medialock = 1;
-	}
-
-	if (found_cnt < MAX_UNITS  &&  full_duplex[found_cnt] > 0)
-		tp->full_duplex = full_duplex[found_cnt];
-
-	if (tp->full_duplex) {
-		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
-		mdio_write(dev, tp->phys[0], 4, 0x141);
-		tp->duplex_lock = 1;
-	}
-
-	/* The Rtl8129-specific entries in the device structure. */
-	dev->open = &rtl8129_open;
-	dev->hard_start_xmit = &rtl8129_start_xmit;
-	dev->tx_timeout = &rtl8129_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->stop = &rtl8129_close;
-	dev->get_stats = &rtl8129_get_stats;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
-
-	return dev;
-}
-
-/* Serial EEPROM section. */
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
-#define EE_CS			0x08	/* EEPROM chip select. */
-#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
-#define EE_WRITE_0		0x00
-#define EE_WRITE_1		0x02
-#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
-#define EE_ENB			(0x80 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
-
-#define eeprom_delay()	inl(ee_addr)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD	(5 << 6)
-#define EE_READ_CMD		(6 << 6)
-#define EE_ERASE_CMD	(7 << 6)
-
-static int read_eeprom(long ioaddr, int location)
-{
-	int i;
-	unsigned retval = 0;
-	long ee_addr = ioaddr + Cfg9346;
-	int read_cmd = location | EE_READ_CMD;
-
-	outb(EE_ENB & ~EE_CS, ee_addr);
-	outb(EE_ENB, ee_addr);
-
-	/* Shift the read command bits out. */
-	for (i = 10; i >= 0; i--) {
-		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-		outb(EE_ENB | dataval, ee_addr);
-		eeprom_delay();
-		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
-	}
-	outb(EE_ENB, ee_addr);
-	eeprom_delay();
-
-	for (i = 16; i > 0; i--) {
-		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
-		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
-		outb(EE_ENB, ee_addr);
-		eeprom_delay();
-	}
-
-	/* Terminate the EEPROM access. */
-	outb(~EE_CS, ee_addr);
-	return retval;
-}
-
-/* MII serial management: mostly bogus for now. */
-/* Read and write the MII management registers using software-generated
-   serial MDIO protocol.
-   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
-#define MDIO_DIR		0x80
-#define MDIO_DATA_OUT	0x04
-#define MDIO_DATA_IN	0x02
-#define MDIO_CLK		0x01
-#define MDIO_WRITE0 (MDIO_DIR)
-#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
-
-#define mdio_delay()	inb(mdio_addr)
-
-static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,
-								 NWayLPAR, NWayExpansion, 0 };
-
-/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync(long mdio_addr)
-{
-	int i;
-
-	for (i = 32; i >= 0; i--) {
-		outb(MDIO_WRITE1, mdio_addr);
-		mdio_delay();
-		outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return;
-}
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	long mdio_addr = dev->base_addr + MII_SMI;
-	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	int retval = 0;
-	int i;
-
-	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		return location < 8 && mii_2_8139_map[location] ?
-			inw(dev->base_addr + mii_2_8139_map[location]) : 0;
-	}
-	mdio_sync(mdio_addr);
-	/* Shift the read command bits out. */
-	for (i = 15; i >= 0; i--) {
-		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-
-		outb(MDIO_DIR | dataval, mdio_addr);
-		mdio_delay();
-		outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outb(0, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
-		outb(MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	long mdio_addr = dev->base_addr + MII_SMI;
-	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-	int i;
-
-	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		if (location < 8  &&  mii_2_8139_map[location])
-			outw(value, dev->base_addr + mii_2_8139_map[location]);
-		return;
-	}
-	mdio_sync(mdio_addr);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-		outb(dataval, mdio_addr);
-		mdio_delay();
-		outb(dataval | MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Clear out extra bits. */
-	for (i = 2; i > 0; i--) {
-		outb(0, mdio_addr);
-		mdio_delay();
-		outb(MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return;
-}
-
-
-static int
-rtl8129_open(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int i;
-
-	/* Soft reset the chip. */
-	outb(CmdReset, ioaddr + ChipCmd);
-
-	if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
-		return -EAGAIN;
-	}
-
-	MOD_INC_USE_COUNT;
-
-	tp->tx_bufs = pci_alloc_consistent(tp->pdev,
-									   TX_BUF_SIZE * NUM_TX_DESC,
-									   &tp->tx_bufs_dma);
-	tp->rx_ring = pci_alloc_consistent(tp->pdev,
-									   RX_BUF_LEN + 16,
-									   &tp->rx_ring_dma);
-	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {
-		free_irq(dev->irq, dev);
-		if (tp->tx_bufs)
-			pci_free_consistent(tp->pdev,
-								TX_BUF_SIZE * NUM_TX_DESC,
-								tp->tx_bufs, tp->tx_bufs_dma);
-		if (tp->rx_ring)
-			pci_free_consistent(tp->pdev,
-								RX_BUF_LEN + 16,
-								tp->rx_ring, tp->rx_ring_dma);
-		if (rtl8129_debug > 0)
-			printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
-				   dev->name, RX_BUF_LEN);
-		return -ENOMEM;
-	}
-	rtl8129_init_ring(dev);
-
-	/* Check that the chip has finished the reset. */
-	for (i = 1000; i > 0; i--)
-		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
-			break;
-
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
-
-	/* Must enable Tx/Rx before setting transfer thresholds! */
-	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
-		 ioaddr + RxConfig);
-	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
-	tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
-
-	tp->full_duplex = tp->duplex_lock;
-	if (tp->phys[0] >= 0  ||  (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) {
-		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-		if (mii_reg5 == 0xffff)
-			;					/* Not there */
-		else if ((mii_reg5 & 0x0100) == 0x0100
-				 || (mii_reg5 & 0x00C0) == 0x0040)
-			tp->full_duplex = 1;
-		if (rtl8129_debug > 1)
-			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
-				   " auto-negotiated partner ability %4.4x.\n", dev->name,
-				   mii_reg5 == 0 ? "" :
-				   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
-				   tp->full_duplex ? "full" : "half", mii_reg5);
-	}
-
-	outb(0xC0, ioaddr + Cfg9346);
-	outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-	outb(0x00, ioaddr + Cfg9346);
-
-	outl(tp->rx_ring_dma, ioaddr + RxBuf);
-
-	/* Start the chip's Tx and Rx process. */
-	outl(0, ioaddr + RxMissed);
-	set_rx_mode(dev);
-
-	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-
-	/* Enable all known interrupts by setting the interrupt mask. */
-	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
-
-	if (rtl8129_debug > 1)
-		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
-			   " GP Pins %2.2x %s-duplex.\n",
-			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
-			   tp->full_duplex ? "full" : "half");
-
-	/* Set the timer to switch to check for link beat and perhaps switch
-	   to an alternate media type. */
-	init_timer(&tp->timer);
-	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
-	tp->timer.data = (unsigned long)dev;
-	tp->timer.function = &rtl8129_timer;
-	add_timer(&tp->timer);
-
-	return 0;
-}
-
-static void rtl8129_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;
-	int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-
-	if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {
-		int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-		if (tp->full_duplex != duplex) {
-			tp->full_duplex = duplex;
-			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-				   " partner ability of %4.4x.\n", dev->name,
-				   tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);
-			outb(0xC0, ioaddr + Cfg9346);
-			outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-			outb(0x00, ioaddr + Cfg9346);
-		}
-	}
-	/* Check for bogusness. */
-	if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
-		int status = inw(ioaddr + IntrStatus);
-		if (status & (TxOK | RxOK)) {	/* Double check */
-			printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
-				   dev->name, status);
-			rtl8129_interrupt(dev->irq, dev, 0);
-		}
-	}
-	if (test_bit(LINK_STATE_XOFF, &dev->state) &&
-		(jiffies - dev->trans_start) >= 2*TX_TIMEOUT)
-		rtl8129_tx_timeout(dev);
-
-#if 0
-	if (tp->twistie) {
-		unsigned int CSCRval = inw(ioaddr + CSCR);		/* Read link status. */
-		if (tp->twistie == 1) {
-			if (CSCRval & CSCR_LinkOKBit) {
-				outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
-				tp->twistie = 2;
-				next_tick = HZ/10;
-			} else {
-				outw(CSCR_LinkDownCmd, ioaddr + CSCR);
-				outl(FIFOTMS_default,ioaddr + FIFOTMS);
-				outl(PARA78_default ,ioaddr + PARA78);
-				outl(PARA7c_default ,ioaddr + PARA7c);
-				tp->twistie = 0;
-			}
-		} else if (tp->twistie == 2) {
-			int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12;
-			int row;
-			if (linkcase >= 0x7000) row = 3;
-			else if (linkcase >= 0x3000) row = 2;
-			else if (linkcase >= 0x1000) row = 1;
-			else row = 0;
-			tp->twistie == row + 3;
-			outw(0,ioaddr+FIFOTMS);
-			outl(param[row][0], ioaddr+PARA7c);
-			tp->twist_cnt = 1;
-		} else {
-			outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c);
-			if (++tp->twist_cnt < 4) {
-				next_tick = HZ/10;
-			} else if (tp->twistie-3 == 3) {
-				if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) {
-					outl(PARA7c_xxx, ioaddr+PARA7c);
-					next_tick = HZ/10; 		/* 100ms. */
-					outl(FIFOTMS_default, ioaddr+FIFOTMS);
-					outl(PARA78_default,  ioaddr+PARA78);
-					outl(PARA7c_default,  ioaddr+PARA7c);
-					tp->twistie == 3 + 3;
-					outw(0,ioaddr+FIFOTMS);
-					outl(param[3][0], ioaddr+PARA7c);
-					tp->twist_cnt = 1;
-				}
-			}
-		}
-	}
-#endif
-
-	if (rtl8129_debug > 2) {
-		if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
-			printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
-				   dev->name, inb(ioaddr + GPPinData));
-		else
-			printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
-				   dev->name, inw(ioaddr + NWayLPAR));
-		printk(KERN_DEBUG"%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
-			   " RxStatus %4.4x.\n",
-			   dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
-			   inl(ioaddr + RxEarlyStatus));
-		printk(KERN_DEBUG"%s:  Chip config %2.2x %2.2x.\n",
-			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
-	}
-
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
-}
-
-static void rtl8129_tx_timeout(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int mii_reg, i;
-
-	if (rtl8129_debug > 0)
-		printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x "
-			   "media %2.2x.\n",
-			   dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),
-			   inb(ioaddr + GPPinData));
-
-	/* Disable interrupts by clearing the interrupt mask. */
-	outw(0x0000, ioaddr + IntrMask);
-	/* Emit info to figure out what went wrong. */
-	printk("%s: Tx queue start entry %d  dirty entry %d.\n",
-		   dev->name, tp->cur_tx, tp->dirty_tx);
-	for (i = 0; i < NUM_TX_DESC; i++)
-		printk(KERN_DEBUG"%s:  Tx descriptor %d is %8.8x.%s\n",
-			   dev->name, i, inl(ioaddr + TxStatus0 + i*4),
-			   i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
-	printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
-	for (mii_reg = 0; mii_reg < 8; mii_reg++)
-		printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));
-	printk(".\n");
-
-	/* Soft reset the chip. */
-	outb(CmdReset, ioaddr + ChipCmd);
-	/* Check that the chip has finished the reset. */
-	for (i = 1000; i > 0; i--)
-		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
-			break;
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
-
-	outb(0x00, ioaddr + Cfg9346);
-	tp->cur_rx = 0;
-	/* Must enable Tx/Rx before setting transfer thresholds! */
-	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
-		 ioaddr + RxConfig);
-	outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
-	set_rx_mode(dev);
-	{							/* Save the unsent Tx packets. */
-		struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
-		int j;
-		for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) {
-			struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC];
-
-			saved_skb[j] = rp->skb;
-			if (rp->mapping != 0) {
-				pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len);
-				rp->mapping = 0;
-			}
-		}
-		tp->dirty_tx = tp->cur_tx = 0;
-
-		for (i = 0; i < j; i++) {
-			skb = tp->tx_info[i].skb = saved_skb[i];
-			if ((long)skb->data & 3) {		/* Must use alignment buffer. */
-				memcpy(tp->tx_buf[i], skb->data, skb->len);
-				outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs),
-					 ioaddr + TxAddr0 + i*4);
-			} else {
-				tp->tx_info[i].mapping =
-					pci_map_single(tp->pdev, skb->data, skb->len);
-				outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);
-			}
-			/* Note: the chip doesn't have auto-pad! */
-			outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-				 ioaddr + TxStatus0 + i*4);
-		}
-		tp->cur_tx = i;
-		while (i < NUM_TX_DESC) {
-			tp->tx_info[i].skb = NULL;
-			tp->tx_info[i].mapping = 0;
-			i++;
-		}
-		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
-			netif_wake_queue(dev);
-			tp->tx_full = 0;
-		} else {
-			tp->tx_full = 1;
-		}
-	}
-
-	dev->trans_start = jiffies;
-	tp->stats.tx_errors++;
-	/* Enable all known interrupts by setting the interrupt mask. */
-	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
-	return;
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-rtl8129_init_ring(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	int i;
-
-	tp->tx_full = 0;
-	tp->cur_rx = 0;
-	tp->dirty_tx = tp->cur_tx = 0;
-
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
-		tp->tx_info[i].skb = NULL;
-		tp->tx_info[i].mapping = 0;
-	}
-}
-
-static int
-rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int entry;
-
-	netif_stop_queue(dev);
-
-	/* Calculate the next Tx descriptor entry. */
-	entry = tp->cur_tx % NUM_TX_DESC;
-
-	tp->tx_info[entry].skb = skb;
-	if ((long)skb->data & 3) {			/* Must use alignment buffer. */
-		tp->tx_info[entry].mapping = 0;
-		memcpy(tp->tx_buf[entry], skb->data, skb->len);
-		outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs),
-			 ioaddr + TxAddr0 + entry*4);
-	} else {
-		tp->tx_info[entry].mapping =
-			pci_map_single(tp->pdev, skb->data, skb->len);
-		outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4);
-	}
-	/* Note: the chip doesn't have auto-pad! */
-	outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-		 ioaddr + TxStatus0 + entry*4);
-
-	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {	/* Typical path */
-		netif_start_queue(dev);
-	} else {
-		tp->tx_full = 1;
-	}
-
-	dev->trans_start = jiffies;
-	if (rtl8129_debug > 4)
-		printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
-			   dev->name, skb->data, (int)skb->len, entry);
-
-	return 0;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct net_device *dev = (struct net_device *)dev_instance;
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	int boguscnt = max_interrupt_work;
-	int status, link_changed = 0;
-	long ioaddr = dev->base_addr;
-
-	do {
-		status = inw(ioaddr + IntrStatus);
-		/* Acknowledge all of the current interrupt sources ASAP, but
-		   an first get an additional status bit from CSCR. */
-		if ((status & RxUnderrun)  &&  inw(ioaddr+CSCR) & CSCR_LinkChangeBit)
-			link_changed = 1;
-		outw(status, ioaddr + IntrStatus);
-
-		if (rtl8129_debug > 4)
-			printk(KERN_DEBUG"%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
-				   dev->name, status, inw(ioaddr + IntrStatus));
-
-		if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver
-					   |TxErr|TxOK|RxErr|RxOK)) == 0)
-			break;
-
-		if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */
-			rtl8129_rx(dev);
-
-		if (status & (TxOK | TxErr)) {
-			unsigned int dirty_tx = tp->dirty_tx;
-
-			while (tp->cur_tx - dirty_tx > 0) {
-				int entry = dirty_tx % NUM_TX_DESC;
-				int txstatus = inl(ioaddr + TxStatus0 + entry*4);
-
-				if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))
-					break;			/* It still hasn't been Txed */
-
-				/* Note: TxCarrierLost is always asserted at 100mbps. */
-				if (txstatus & (TxOutOfWindow | TxAborted)) {
-					/* There was an major error, log it. */
-					if (rtl8129_debug > 1)
-						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
-							   dev->name, txstatus);
-					tp->stats.tx_errors++;
-					if (txstatus&TxAborted) {
-						tp->stats.tx_aborted_errors++;
-						outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);
-					}
-					if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;
-					if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-					if ((txstatus & 0x0f000000) == 0x0f000000)
-						tp->stats.collisions16++;
-#endif
-				} else {
-					if (txstatus & TxUnderrun) {
-						/* Add 64 to the Tx FIFO threshold. */
-						if (tp->tx_flag <  0x00300000)
-							tp->tx_flag += 0x00020000;
-						tp->stats.tx_fifo_errors++;
-					}
-					tp->stats.collisions += (txstatus >> 24) & 15;
-#if LINUX_VERSION_CODE > 0x20119
-					tp->stats.tx_bytes += txstatus & 0x7ff;
-#endif
-					tp->stats.tx_packets++;
-				}
-
-				if (tp->tx_info[entry].mapping != 0) {
-					pci_unmap_single(tp->pdev,
-									 tp->tx_info[entry].mapping,
-									 tp->tx_info[entry].skb->len);
-					tp->tx_info[entry].mapping = 0;
-				}
-
-				/* Free the original skb. */
-				dev_kfree_skb_irq(tp->tx_info[entry].skb);
-				tp->tx_info[entry].skb = NULL;
-				if (tp->tx_full) {
-					/* The ring is no longer full, wake the queue. */
-					tp->tx_full = 0;
-					netif_wake_queue(dev);
-				}
-				dirty_tx++;
-			}
-
-#ifndef final_version
-			if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-				printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
-				dirty_tx += NUM_TX_DESC;
-			}
-#endif
-			tp->dirty_tx = dirty_tx;
-		}
-
-		/* Check uncommon events with one test. */
-		if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
-					  |TxErr|RxErr)) {
-			if (rtl8129_debug > 2)
-				printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",
-					   dev->name, status);
-
-			if (status == 0xffffffff)
-				break;
-			/* Update the error count. */
-			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-			outl(0, ioaddr + RxMissed);
-
-			if ((status & RxUnderrun)  &&  link_changed  &&
-				(rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) {
-				/* Really link-change on new chips. */
-				int lpar = inw(ioaddr + NWayLPAR);
-				int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; 
-				if (tp->full_duplex != duplex) {
-					tp->full_duplex = duplex;
-					outb(0xC0, ioaddr + Cfg9346);
-					outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-					outb(0x00, ioaddr + Cfg9346);
-				}
-				status &= ~RxUnderrun;
-			}
-			if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
-				tp->stats.rx_errors++;
-
-			if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
-			if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;
-			if (status & RxOverflow) {
-				tp->stats.rx_over_errors++;
-				tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
-				outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
-			}
-			if (status & PCIErr) {
-				u32 pci_cmd_status;
-				pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn,
-										  PCI_COMMAND, &pci_cmd_status);
-
-				printk(KERN_ERR "%s: PCI Bus error %4.4x.\n",
-					   dev->name, pci_cmd_status);
-			}
-		}
-		if (--boguscnt < 0) {
-			printk(KERN_WARNING"%s: Too much work at interrupt, "
-				   "IntrStatus=0x%4.4x.\n",
-				   dev->name, status);
-			/* Clear all interrupt sources. */
-			outw(0xffff, ioaddr + IntrStatus);
-			break;
-		}
-	} while (1);
-
-	if (rtl8129_debug > 3)
-		printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
-			   dev->name, inl(ioaddr + IntrStatus));
-	return;
-}
-
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
-   field alignments and semantics. */
-static int rtl8129_rx(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	unsigned char *rx_ring = tp->rx_ring;
-	u16 cur_rx = tp->cur_rx;
-
-	if (rtl8129_debug > 4)
-		printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"
-			   " free to %4.4x, Cmd %2.2x.\n",
-			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
-			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
-
-	while ((inb(ioaddr + ChipCmd) & 1) == 0) {
-		int ring_offset = cur_rx % RX_BUF_LEN;
-		u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset));
-		int rx_size = rx_status >> 16;
-
-		if (rtl8129_debug > 4) {
-			int i;
-			printk(KERN_DEBUG"%s:  rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",
-				   dev->name, rx_status, rx_size, cur_rx);
-			printk(KERN_DEBUG"%s: Frame contents ", dev->name);
-			for (i = 0; i < 70; i++)
-				printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i]));
-			printk(".\n");
-		}
-		if (rx_status & RxTooLong) {
-			if (rtl8129_debug > 0)
-				printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",
-					   dev->name, rx_status);
-			tp->stats.rx_length_errors++;
-		} else if (rx_status &
-				   (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
-			if (rtl8129_debug > 1)
-				printk(KERN_DEBUG"%s: Ethernet frame had errors,"
-					   " status %4.4x.\n", dev->name, rx_status);
-			tp->stats.rx_errors++;
-			if (rx_status & (RxBadSymbol|RxBadAlign))
-				tp->stats.rx_frame_errors++;
-			if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;
-			if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
-			/* Reset the receiver, based on RealTek recommendation. (Bug?) */
-			tp->cur_rx = 0;
-			outb(CmdTxEnb, ioaddr + ChipCmd);
-			outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-			outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |
-				 (RX_DMA_BURST<<8), ioaddr + RxConfig);
-		} else {
-			/* Malloc up new buffer, compatible with net-2e. */
-			/* Omit the four octet CRC from the length. */
-			struct sk_buff *skb;
-
-			skb = dev_alloc_skb(rx_size + 2);
-			if (skb == NULL) {
-				printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",
-					   dev->name);
-				/* We should check that some rx space is free.
-				   If not, free one and mark stats->rx_dropped++. */
-				tp->stats.rx_dropped++;
-				break;
-			}
-			skb->dev = dev;
-			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */
-			if (ring_offset+rx_size+4 > RX_BUF_LEN) {
-				int semi_count = RX_BUF_LEN - ring_offset - 4;
-				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
-					   semi_count);
-				memcpy(skb_put(skb, rx_size-semi_count), rx_ring,
-					   rx_size-semi_count);
-				if (rtl8129_debug > 4) {
-					int i;
-					printk(KERN_DEBUG"%s:  Frame wrap @%d",
-						   dev->name, semi_count);
-					for (i = 0; i < 16; i++)
-						printk(" %2.2x", le32_to_cpu(rx_ring[i]));
-					printk(".\n");
-					memset(rx_ring, 0xcc, 16);
-				}
-			} else {
-#if 1  /* USE_IP_COPYSUM */
-				eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],
-								 rx_size, 0);
-				skb_put(skb, rx_size);
-#else
-				memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
-					   rx_size);
-#endif
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-#if LINUX_VERSION_CODE > 0x20119
-			tp->stats.rx_bytes += rx_size;
-#endif
-			tp->stats.rx_packets++;
-		}
-
-		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
-		outw(cur_rx - 16, ioaddr + RxBufPtr);
-	}
-	if (rtl8129_debug > 4)
-		printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"
-			   " free to %4.4x, Cmd %2.2x.\n",
-			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
-			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
-	tp->cur_rx = cur_rx;
-	return 0;
-}
-
-static int
-rtl8129_close(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	int i;
-
-	netif_stop_queue(dev);
-
-	if (rtl8129_debug > 1)
-		printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
-			   dev->name, inw(ioaddr + IntrStatus));
-
-	/* Disable interrupts by clearing the interrupt mask. */
-	outw(0x0000, ioaddr + IntrMask);
-
-	/* Stop the chip's Tx and Rx DMA processes. */
-	outb(0x00, ioaddr + ChipCmd);
-
-	/* Update the error counts. */
-	tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-	outl(0, ioaddr + RxMissed);
-
-	del_timer(&tp->timer);
-
-	free_irq(dev->irq, dev);
-
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		struct sk_buff *skb = tp->tx_info[i].skb;
-		dma_addr_t mapping = tp->tx_info[i].mapping;
-
-		if (skb) {
-			if (mapping)
-				pci_unmap_single(tp->pdev, mapping, skb->len);
-			dev_kfree_skb(skb);
-		}
-		tp->tx_info[i].skb = NULL;
-		tp->tx_info[i].mapping = 0;
-	}
-	pci_free_consistent(tp->pdev, RX_BUF_LEN + 16,
-						tp->rx_ring, tp->rx_ring_dma);
-	pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC,
-						tp->tx_bufs, tp->tx_bufs_dma);
-	tp->rx_ring = NULL;
-	tp->tx_bufs = NULL;
-
-	/* Green! Put the chip in low-power mode. */
-	outb(0xC0, ioaddr + Cfg9346);
-	outb(0x03, ioaddr + Config1);
-	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
-
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
-
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	u16 *data = (u16 *)&rq->ifr_data;
-
-	switch(cmd) {
-	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = tp->phys[0] & 0x3f;
-		/* Fall Through */
-	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		data[3] = mdio_read(dev, data[0], data[1] & 0x1f);
-		return 0;
-	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-static struct enet_statistics *
-rtl8129_get_stats(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	if (test_bit(LINK_STATE_START, &dev->state)) {
-		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-		outl(0, ioaddr + RxMissed);
-	}
-
-	return &tp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   This routine is not state sensitive and need not be SMP locked. */
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
-	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
-	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
-};
-
-static void set_rx_mode(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	u32 mc_filter[2];		 /* Multicast hash filter */
-	int i, rx_mode;
-
-	if (rtl8129_debug > 3)
-		printk(KERN_DEBUG"%s:   set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
-			   dev->name, dev->flags, inl(ioaddr + RxConfig));
-
-	/* Note: do not reorder, GCC is clever about common statements. */
-	if (dev->flags & IFF_PROMISC) {
-		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);
-		rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys;
-		mc_filter[1] = mc_filter[0] = 0xffffffff;
-	} else if ((dev->mc_count > multicast_filter_limit)
-			   ||  (dev->flags & IFF_ALLMULTI)) {
-		/* Too many to filter perfectly -- accept all multicasts. */
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-		mc_filter[1] = mc_filter[0] = 0xffffffff;
-	} else {
-		struct dev_mc_list *mclist;
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-		mc_filter[1] = mc_filter[0] = 0;
-		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next)
-			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
-	}
-	/* We can safely update without stopping the chip. */
-	outb(rx_mode, ioaddr + RxConfig);
-	outl(mc_filter[0], ioaddr + MAR0 + 0);
-	outl(mc_filter[1], ioaddr + MAR0 + 4);
-	return;
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-	return rtl8139_probe();
-}
-
-void
-cleanup_module(void)
-{
-	struct net_device *next_dev;
-
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_rtl8129_dev) {
-		struct rtl8129_private *tp =
-			(struct rtl8129_private *)root_rtl8129_dev->priv;
-		next_dev = tp->next_module;
-		unregister_netdev(root_rtl8129_dev);
-		release_region(root_rtl8129_dev->base_addr,
-					   pci_tbl[tp->chip_id].io_size);
-		kfree(tp);
-		kfree(root_rtl8129_dev);
-		root_rtl8129_dev = next_dev;
-	}
-}
-
-#endif  /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff -u --recursive --new-file v2.3.44/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.3.44/linux/drivers/net/seeq8005.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/net/seeq8005.c	Sat Feb 12 15:45:05 2000
@@ -83,6 +83,7 @@
 
 static int seeq8005_probe1(struct net_device *dev, int ioaddr);
 static int seeq8005_open(struct net_device *dev);
+static void seeq8005_timeout(struct net_device *dev);
 static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void seeq8005_rx(struct net_device *dev);
@@ -324,9 +325,11 @@
 
 	dev->open		= seeq8005_open;
 	dev->stop		= seeq8005_close;
-	dev->hard_start_xmit = seeq8005_send_packet;
-	dev->get_stats	= seeq8005_get_stats;
-	dev->set_multicast_list = &set_multicast_list;
+	dev->hard_start_xmit 	= seeq8005_send_packet;
+	dev->tx_timeout		= seeq8005_timeout;
+	dev->watchdog_timeo	= HZ/20;
+	dev->get_stats		= seeq8005_get_stats;
+	dev->set_multicast_list = set_multicast_list;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
@@ -344,8 +347,7 @@
    registers that "should" only need to be set once at boot, so that
    there is non-reboot way to recover if something goes wrong.
    */
-static int
-seeq8005_open(struct net_device *dev)
+static int seeq8005_open(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
@@ -363,46 +365,34 @@
 
 	lp->open_time = jiffies;
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	netif_start_queue(dev);
 	return 0;
 }
 
-static int
-seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void seeq8005_timeout(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+		   tx_done(dev) ? "IRQ conflict" : "network cable problem");
+	/* Try to restart the adaptor. */
+	seeq8005_init(dev, 1);
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
 	struct net_local *lp = (struct net_local *)dev->priv;
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char *buf = skb->data;
 
-	if (dev->tbusy) {
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		printk("%s: transmit timed out, %s?\n", dev->name,
-			   tx_done(dev) ? "IRQ conflict" : "network cable problem");
-		/* Try to restart the adaptor. */
-		seeq8005_init(dev, 1);
-		dev->tbusy=0;
-		dev->trans_start = jiffies;
-	}
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-		printk("%s: Transmitter access conflict.\n", dev->name);
-	else {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
-
-		hardware_send_packet(dev, buf, length); 
-		dev->trans_start = jiffies;
-		lp->stats.tx_bytes += length;
-	}
+	/* Block a timer-based transmit from overlapping */
+	netif_stop_queue(dev);
+	
+	hardware_send_packet(dev, buf, length); 
+	dev->trans_start = jiffies;
+	lp->stats.tx_bytes += length;
 	dev_kfree_skb (skb);
-
 	/* You might need to clean up and record Tx statistics here. */
 
 	return 0;
@@ -410,22 +400,12 @@
 
 /* The typical workload of the driver:
    Handle the network interface interrupts. */
-static void
-seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
 	struct net_local *lp;
 	int ioaddr, status, boguscount = 0;
 
-	if (dev == NULL) {
-		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
-	
-	if (dev->interrupt)
-		printk ("%s: Re-entering the interrupt handler.\n", dev->name);
-	dev->interrupt = 1;
-
 	ioaddr = dev->base_addr;
 	lp = (struct net_local *)dev->priv;
 
@@ -444,8 +424,7 @@
 		if (status & SEEQSTAT_TX_INT) {
 			outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
 			lp->stats.tx_packets++;
-			dev->tbusy = 0;
-			mark_bh(NET_BH);	/* Inform upper layers. */
+			netif_wake_queue(dev);	/* Inform upper layers. */
 		}
 		if (status & SEEQSTAT_RX_INT) {
 			/* Got a packet(s). */
@@ -457,13 +436,10 @@
 	if(net_debug>2) {
 		printk("%s: eoi\n",dev->name);
 	}
-	dev->interrupt = 0;
-	return;
 }
 
 /* We have a good packet(s), get it/them out of the buffers. */
-static void
-seeq8005_rx(struct net_device *dev)
+static void seeq8005_rx(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int boguscount = 10;
@@ -561,17 +537,15 @@
 }
 
 /* The inverse routine to net_open(). */
-static int
-seeq8005_close(struct net_device *dev)
+static int seeq8005_close(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 
 	lp->open_time = 0;
 
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
+	
 	/* Flush the Tx and disable Rx here. */
 	outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
 
@@ -598,8 +572,7 @@
    num_addrs > 0	Multicast mode, receive normal and MC packets, and do
 			best-effort filtering.
  */
-static void
-set_multicast_list(struct net_device *dev)
+static void set_multicast_list(struct net_device *dev)
 {
 /*
  * I _could_ do up to 6 addresses here, but won't (yet?)
diff -u --recursive --new-file v2.3.44/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- v2.3.44/linux/drivers/net/sis900.c	Sat Feb 12 11:22:10 2000
+++ linux/drivers/net/sis900.c	Sun Feb 13 18:51:08 2000
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.06.03	Dec 23 1999
+   Revision:	1.06.04	Feb 11 2000
    
    Modified from the driver which is originally written by Donald Becker. 
    
@@ -135,7 +135,7 @@
 	int LinkOn;
 };
 
-MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>");
+MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
 MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver");
 MODULE_PARM(multicast_filter_limit, "i");
 MODULE_PARM(max_interrupt_work, "i");
@@ -257,7 +257,7 @@
 	net_dev->irq = irq;
 	sis_priv->pci_dev = pci_dev;
 	sis_priv->mac = mac;
-	sis_priv->lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_init(&sis_priv->lock);
 
 	/* probe for mii transciver */
 	if (sis900_mii_probe(net_dev) == 0) {
@@ -668,8 +668,8 @@
 		next_tick = 5*HZ;
 		/* change what cur_phy means */
 		if (mii_phy->phy_addr != sis_priv->cur_phy) {
-			printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name,
-			       mii_phy->chip_info->name);
+			printk(KERN_INFO "%s: Changing transceiver to %s\n",
+			       net_dev->name, mii_phy->chip_info->name);
 			status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
 			mdio_write(net_dev, sis_priv->cur_phy, 
 				   MII_CONTROL, status | MII_CNTL_ISOLATE);
@@ -798,9 +798,10 @@
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0x0000, ioaddr + imr);
 
-	/* discard unsent packets, should this code section be protected by
-	   cli(), sti() ?? */
+	/* use spinlock to prevent interrupt handler accessing buffer ring */
 	spin_lock_irqsave(&sis_priv->lock, flags);
+
+	/* discard unsent packets */
 	sis_priv->dirty_tx = sis_priv->cur_tx = 0;
 	for (i = 0; i < NUM_TX_DESC; i++) {
 		if (sis_priv->tx_skbuff[i] != NULL) {
@@ -811,13 +812,15 @@
 			sis_priv->stats.tx_dropped++;
 		}
 	}
+	sis_priv->tx_full = 0;
+	netif_wake_queue(net_dev);
+
 	spin_unlock_irqrestore(&sis_priv->lock, flags);
 
 	net_dev->trans_start = jiffies;
-	sis_priv->tx_full = 0;
-	netif_start_queue(net_dev);
 
 	/* FIXME: Should we restart the transmission thread here  ?? */
+	outl(TxENA, ioaddr + cr);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
 	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
@@ -830,6 +833,9 @@
 	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
 	long ioaddr = net_dev->base_addr;
 	unsigned int  entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sis_priv->lock, flags);
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = sis_priv->cur_tx % NUM_TX_DESC;
@@ -841,14 +847,16 @@
 	outl(TxENA, ioaddr + cr);
 
 	if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
-		/* Typical path, clear tbusy to indicate more 
-		   transmission is possible */
+		/* Typical path, tell upper layer that more transmission is possible */
 		netif_start_queue(net_dev);
 	} else {
-		/* no more transmit descriptor avaiable, tbusy remain set */
+		/* buffer full, tell upper layer no more transmission */
 		sis_priv->tx_full = 1;
+		netif_stop_queue(net_dev);
 	}
 
+	spin_unlock_irqrestore(&sis_priv->lock, flags);
+
 	net_dev->trans_start = jiffies;
 
 	if (sis900_debug > 3)
@@ -922,7 +930,7 @@
 	if (sis900_debug > 3)
 		printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
 		       "status:0x%8.8x\n",
-		       sis_priv->cur_rx, sis_priv->dirty_rx,rx_status);
+		       sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);
 	
 	while (rx_status & OWN) {
 		unsigned int rx_size;
@@ -1060,8 +1068,8 @@
 	
 	if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) && 
 	    sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
-		/* The ring is no longer full, clear tbusy, tx_full and
-		   schedule more transmission by marking NET_BH */
+		/* The ring is no longer full, clear tx_full and schedule more transmission
+		   by netif_wake_queue(net_dev) */
 		sis_priv->tx_full = 0;
 		netif_wake_queue (net_dev);
 	}
diff -u --recursive --new-file v2.3.44/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.3.44/linux/drivers/net/sk_g16.c	Thu Feb 10 17:11:11 2000
+++ linux/drivers/net/sk_g16.c	Sun Feb 13 18:20:21 2000
@@ -472,6 +472,7 @@
 int          SK_init(struct net_device *dev);
 static int   SK_probe(struct net_device *dev, short ioaddr);
 
+static void  SK_timeout(struct net_device *dev);
 static int   SK_open(struct net_device *dev);
 static int   SK_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void  SK_interrupt(int irq, void *dev_id, struct pt_regs * regs);
@@ -778,11 +779,13 @@
 
     /* Assign our Device Driver functions */
 
-    dev->open                   = &SK_open;
-    dev->stop                   = &SK_close;
-    dev->hard_start_xmit        = &SK_send_packet;
-    dev->get_stats              = &SK_get_stats;
-    dev->set_multicast_list     = &set_multicast_list;
+    dev->open                   = SK_open;
+    dev->stop                   = SK_close;
+    dev->hard_start_xmit        = SK_send_packet;
+    dev->get_stats              = SK_get_stats;
+    dev->set_multicast_list     = set_multicast_list;
+    dev->tx_timeout		= SK_timeout;
+    dev->watchdog_timeo		= HZ/7;
 
 
     /* Set the generic fields of the device structure */
@@ -1169,30 +1172,18 @@
  *     YY/MM/DD  uid  Description
 -*/
 
-static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
+static int SK_timeout(struct net_device *dev)
 {
-    struct priv *p = (struct priv *) dev->priv;
-    struct tmd *tmdp;
-
-    if (test_bit(LINK_STATE_XOFF, &dev->flags))
-    {
-	/* if Transmitter more than 150ms busy -> time_out */
-
-	int tickssofar = jiffies - dev->trans_start;
-	if (tickssofar < 15)
-	{
-	    return 1;                    /* We have to try transmit later */
-	}
-
-	printk("%s: xmitter timed out, try to restart!\n", dev->name);
-
+	printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name);
 	SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */
-
 	netif_start_queue(dev);		 /* Clear Transmitter flag */
-
 	dev->trans_start = jiffies;      /* Mark Start of transmission */
+}
 
-    }
+static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+    struct priv *p = (struct priv *) dev->priv;
+    struct tmd *tmdp;
 
     PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", 
 	    SK_NAME, SK_read_reg(CSR0)));
diff -u --recursive --new-file v2.3.44/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.3.44/linux/drivers/net/smc-mca.c	Mon Oct  4 15:49:29 1999
+++ linux/drivers/net/smc-mca.c	Sat Feb 12 15:45:05 2000
@@ -414,9 +414,8 @@
 {
 	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
 
-	dev->start = 0;
-	dev->tbusy = 1;
-
+	netif_stop_queue(dev);
+	
 	if (ei_debug > 1)
 		printk("%s: Shutting down ethercard.\n", dev->name);
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.3.44/linux/drivers/net/smc9194.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/smc9194.c	Sat Feb 12 15:45:05 2000
@@ -50,11 +50,8 @@
 static const char *version =
 	"smc9194.c:v0.12 03/06/96 by Erik Stahlman (erik@vt.edu)\n";
 
-#ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -82,22 +79,6 @@
  -------------------------------------------------------------------------*/
 
 /*
- . this is for kernels > 1.2.70
-*/
-#define REALLY_NEW_KERNEL
-#ifndef REALLY_NEW_KERNEL
-#define free_irq( x, y ) free_irq( x )
-#define request_irq( x, y, z, u, v ) request_irq( x, y, z, u )
-#endif
-
-/*
- . Do you want to use this with old kernels.
- . WARNING: this is not well tested.
-#define SUPPORT_OLD_KERNEL
-*/
-
-
-/*
  . Do you want to use 32 bit xfers?  This should work on all chips, as
  . the chipset is designed to accommodate them.
 */
@@ -108,9 +89,10 @@
  .for a slightly different card, you can add it to the array.  Keep in
  .mind that the array must end in zero.
 */
-static unsigned int smc_portlist[] __initdata =
-   { 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
-	  0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0};
+static unsigned int smc_portlist[] __initdata = { 
+	0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
+	0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
+};
 
 /*
  . Wait time for memory to be free.  This probably shouldn't be
@@ -149,12 +131,6 @@
 #endif
 
 
-/* the older versions of the kernel cannot support autoprobing */
-#ifdef SUPPORT_OLD_KERNEL
-#define NO_AUTOPROBE
-#endif
-
-
 /*------------------------------------------------------------------------
  .
  . The internal workings of the driver.  If you are changing anything
@@ -164,9 +140,6 @@
  -------------------------------------------------------------------------*/
 #define CARDNAME "SMC9194"
 
-#ifdef SUPPORT_OLD_KERNEL
-char kernel_version[] = UTS_RELEASE;
-#endif
 
 /* store this information for the driver.. */
 struct smc_local {
@@ -217,6 +190,11 @@
 static int smc_open(struct net_device *dev);
 
 /*
+ . Our watchdog timed out. Called by the networking layer
+*/
+static void smc_timeout(struct net_device *dev);
+
+/*
  . This is called by the kernel to send a packet out into the net.  it's
  . responsible for doing a best-effort send, but if it's simply not possible
  . to send it, the packet gets dropped.
@@ -240,12 +218,12 @@
  . Finally, a call to set promiscuous mode ( for TCPDUMP and related
  . programs ) and multicast modes.
 */
-#ifdef SUPPORT_OLD_KERNEL
-static void smc_set_multicast_list(struct net_device *dev, int num_addrs,
-				 void *addrs);
-#else
 static void smc_set_multicast_list(struct net_device *dev);
-#endif
+
+/*
+ . CRC compute
+ */
+static int crc32( char * s, int length );
 
 /*---------------------------------------------------------------
  .
@@ -256,11 +234,7 @@
 /*
  . Handles the actual interrupt
 */
-#ifdef REALLY_NEW_KERNEL
 static void smc_interrupt(int irq, void *, struct pt_regs *regs);
-#else
-static void smc_interrupt(int irq, struct pt_regs *regs);
-#endif
 /*
  . This is a separate procedure to handle the receipt of a packet, to
  . leave the interrupt code looking slightly cleaner
@@ -321,25 +295,9 @@
 /* this puts the device in an inactive state */
 static void smc_shutdown( int ioaddr );
 
-#ifndef NO_AUTOPROBE
 /* This routine will find the IRQ of the driver if one is not
  . specified in the input to the device.  */
 static int smc_findirq( int ioaddr );
-#endif
-
-/*
-  this routine will set the hardware multicast table to the specified
-  values given it by the higher level routines
-*/
-#ifndef SUPPORT_OLD_KERNEL
-static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list *  );
-static int crc32( char *, int );
-#endif
-
-#ifdef SUPPORT_OLD_KERNEL
-extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_private,
- 			unsigned long *mem_startp );
-#endif
 
 /*
  . Function: smc_reset( int ioaddr )
@@ -442,7 +400,6 @@
 }
 
 
-#ifndef SUPPORT_OLD_KERNEL
 /*
  . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
  . Purpose:
@@ -525,8 +482,6 @@
 	return	crc_value;
 }
 
-#endif
-
 
 /*
  . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
@@ -575,6 +530,7 @@
 		dev_kfree_skb (skb);
 		lp->saved_skb = NULL;
 		/* this IS an error, but, i don't want the skb saved */
+		netif_wake_queue(dev);
 		return 0;
 	}
 	/* either way, a packet is waiting now */
@@ -616,7 +572,7 @@
    	}
 	/* or YES! I can send the packet now.. */
 	smc_hardware_send_packet(dev);
-
+	netif_wake_queue(dev);
 	return 0;
 }
 
@@ -663,7 +619,7 @@
 		printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
 		kfree(skb);
 		lp->saved_skb = NULL;
-		dev->tbusy = 0;
+		netif_wake_queue(dev);
 		return;
 	}
 
@@ -729,8 +685,7 @@
 	dev->trans_start = jiffies;
 
 	/* we can send another packet */
-	dev->tbusy = 0;
-
+	netif_wake_queue(dev);
 
 	return;
 }
@@ -787,7 +742,6 @@
 	return -ENODEV;
 }
 
-#ifndef NO_AUTOPROBE
 /*----------------------------------------------------------------------
  . smc_findirq
  .
@@ -860,7 +814,6 @@
 	/* and return what I found */
 	return autoirq_report( 0 );
 }
-#endif
 
 /*----------------------------------------------------------------------
  . Function: smc_probe( int ioaddr )
@@ -962,14 +915,7 @@
 
 	/* see if I need to initialize the ethernet card structure */
 	if (dev == NULL) {
-#ifdef SUPPORT_OLD_KERNEL
-#ifndef MODULE
-/* note: the old module interface does not support this call */
-		dev = init_etherdev( 0, sizeof( struct smc_local ), 0 );
-#endif
-#else
 		dev = init_etherdev(0, 0);
-#endif
 		if (dev == NULL)
 			return -ENOMEM;
 	}
@@ -1043,7 +989,6 @@
 	 . what (s)he is doing.  No checking is done!!!!
  	 .
 	*/
-#ifndef NO_AUTOPROBE
 	if ( dev->irq < 2 ) {
 		int	trials;
 
@@ -1060,13 +1005,6 @@
 		printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n");
 		return -ENODEV;
 	}
-#else
-	if (dev->irq == 0 ) {
-		printk(CARDNAME
-		": Autoprobing IRQs is not supported for old kernels.\n");
-		return -ENODEV;
-	}
-#endif
 	if (dev->irq == 2) {
 		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
 		 * or don't know which one to set.
@@ -1114,10 +1052,10 @@
 	dev->open		        = smc_open;
 	dev->stop		        = smc_close;
 	dev->hard_start_xmit    	= smc_send_packet;
+	dev->tx_timeout		    	= smc_timeout;
+	dev->watchdog_timeo		= HZ/20;
 	dev->get_stats			= smc_query_statistics;
-#ifdef	HAVE_MULTICAST
-	dev->set_multicast_list 	= &smc_set_multicast_list;
-#endif
+	dev->set_multicast_list 	= smc_set_multicast_list;
 
 	return 0;
 }
@@ -1174,12 +1112,7 @@
 	/* clear out all the junk that was put here before... */
 	memset(dev->priv, 0, sizeof(struct smc_local));
 
-	dev->tbusy 	= 0;
-	dev->interrupt  = 0;
-	dev->start 	= 1;
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 
 	/* reset the hardware */
 
@@ -1211,6 +1144,8 @@
 		address  |= dev->dev_addr[ i ];
 		outw( address, ioaddr + ADDR0 + i );
 	}
+	
+	netif_start_queue(dev);
 	return 0;
 }
 
@@ -1220,38 +1155,29 @@
  . skeleton.c, from Becker.
  .--------------------------------------------------------
 */
+
+static void smc_timeout(struct net_device *dev)
+{
+	/* If we get here, some higher level has decided we are broken.
+	   There should really be a "kick me" function call instead. */
+	printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
+		tx_done(dev) ? "IRQ conflict" :
+		"network cable problem");
+	/* "kick" the adaptor */
+	smc_reset( dev->base_addr );
+	smc_enable( dev->base_addr );
+	dev->trans_start = jiffies;
+	/* clear anything saved */
+	((struct smc_local *)dev->priv)->saved_skb = NULL;
+	netif_wake_queue(dev);
+}
+
 static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	if (dev->tbusy) {
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
-			tx_done(dev) ? "IRQ conflict" :
-			"network cable problem");
-		/* "kick" the adaptor */
-		smc_reset( dev->base_addr );
-		smc_enable( dev->base_addr );
-
-		dev->tbusy = 0;
-		dev->trans_start = jiffies;
-		/* clear anything saved */
-		((struct smc_local *)dev->priv)->saved_skb = NULL;
-	}
-
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");
-		dev_kfree_skb (skb);
-	} else {
-		/* Well, I want to send the packet.. but I don't know
-		   if I can send it right now...  */
-		return smc_wait_to_send_packet( skb, dev );
-	}
-	return 0;
+	netif_stop_queue(dev);
+	/* Well, I want to send the packet.. but I don't know
+	   if I can send it right now...  */
+	return smc_wait_to_send_packet( skb, dev );
 }
 
 /*--------------------------------------------------------------------
@@ -1266,11 +1192,8 @@
  .   and finally restore state.
  .
  ---------------------------------------------------------------------*/
-#ifdef REALLY_NEW_KERNEL
+
 static void smc_interrupt(int irq, void * dev_id,  struct pt_regs * regs)
-#else
-static void smc_interrupt(int irq, struct pt_regs * regs)
-#endif
 {
 	struct net_device *dev 	= dev_id;
 	int ioaddr 		= dev->base_addr;
@@ -1288,20 +1211,6 @@
 
 	PRINTK3((CARDNAME": SMC interrupt started \n"));
 
-	if (dev == NULL) {
-		printk(KERN_WARNING  CARDNAME": irq %d for unknown device.\n",
-			irq);
-		return;
-	}
-
-/* will Linux let this happen ??  If not, this costs some speed */
-	if ( dev->interrupt ) {
-		printk(KERN_WARNING CARDNAME": interrupt inside interrupt.\n");
-		return;
-	}
-
-	dev->interrupt = 1;
-
 	saved_bank = inw( ioaddr + BANK_SELECT );
 
 	SMC_SELECT_BANK(2);
@@ -1346,12 +1255,7 @@
 			lp->stats.collisions += card_stats & 0xF;
 
 			/* these are for when linux supports these statistics */
-#if 0
-			card_stats >>= 4;
-			/* deferred */
-			card_stats >>= 4;
-			/* excess deferred */
-#endif
+
 			SMC_SELECT_BANK( 2 );
 			PRINTK2((KERN_WARNING CARDNAME
 				": TX_BUFFER_EMPTY handled\n"));
@@ -1372,8 +1276,8 @@
 			mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
 
 			/* and let the card send more packets to me */
-			mark_bh( NET_BH );
-
+			netif_wake_queue(dev);
+			
 			PRINTK2((CARDNAME": Handoff done successfully.\n"));
 		} else if (status & IM_RX_OVRN_INT ) {
 			lp->stats.rx_errors++;
@@ -1397,7 +1301,6 @@
 
 	SMC_SELECT_BANK( saved_bank );
 
-	dev->interrupt = 0;
 	PRINTK3((CARDNAME ": Interrupt done\n"));
 	return;
 }
@@ -1462,11 +1365,7 @@
 		if ( status & RS_MULTICAST )
 			lp->stats.multicast++;
 
-#ifdef SUPPORT_OLD_KERNEL
-		skb = alloc_skb( packet_length + 5, GFP_ATOMIC );
-#else
 		skb = dev_alloc_skb( packet_length + 5);
-#endif
 
 		if ( skb == NULL ) {
 			printk(KERN_NOTICE CARDNAME
@@ -1478,18 +1377,12 @@
 		 ! This should work without alignment, but it could be
 		 ! in the worse case
 		*/
-#ifndef SUPPORT_OLD_KERNEL
-		/* TODO: Should I use 32bit alignment here ? */
+
 		skb_reserve( skb, 2 );   /* 16 bit alignment */
-#endif
 
 		skb->dev = dev;
-#ifdef SUPPORT_OLD_KERNEL
-		skb->len = packet_length;
-		data = skb->data;
-#else
 		data = skb_put( skb, packet_length);
-#endif
+
 #ifdef USE_32_BIT
 		/* QUESTION:  Like in the TX routine, do I want
 		   to send the DWORDs or the bytes first, or some
@@ -1516,9 +1409,7 @@
 			print_packet( data, packet_length );
 #endif
 
-#ifndef SUPPORT_OLD_KERNEL
 		skb->protocol = eth_type_trans(skb, dev );
-#endif
 		netif_rx(skb);
 		lp->stats.rx_packets++;
 	} else {
@@ -1616,17 +1507,12 @@
  -----------------------------------------------------*/
 static int smc_close(struct net_device *dev)
 {
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
 	/* clear everything */
 	smc_shutdown( dev->base_addr );
 
 	/* Update the statistics here. */
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif
-
 	return 0;
 }
 
@@ -1648,21 +1534,12 @@
  . promiscuous mode ( for TCPDUMP and cousins ) or accept
  . a select set of multicast packets
 */
-#ifdef SUPPORT_OLD_KERNEL
-static void smc_set_multicast_list( struct net_device * dev,
-			int num_addrs, void * addrs )
-#else
 static void smc_set_multicast_list(struct net_device *dev)
-#endif
 {
 	short ioaddr = dev->base_addr;
 
 	SMC_SELECT_BANK(0);
-#ifdef  SUPPORT_OLD_KERNEL
-	if ( num_addrs < 0 )
-#else
 	if ( dev->flags & IFF_PROMISC )
-#endif
 		outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR );
 
 /* BUG?  I never disable promiscuous mode if multicasting was turned on.
@@ -1674,27 +1551,12 @@
 	   I don't need to zero the multicast table, because the flag is
 	   checked before the table is
 	*/
-#ifdef  SUPPORT_OLD_KERNEL
-	else if ( num_addrs > 20 )	/* arbitrary constant */
-#else
 	else if (dev->flags & IFF_ALLMULTI)
-#endif
 		outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR );
 
 	/* We just get all multicast packets even if we only want them
 	 . from one source.  This will be changed at some future
 	 . point. */
-#ifdef  SUPPORT_OLD_KERNEL
-	else if (num_addrs > 0 ) {
-/* the old kernel support will not have hardware multicast support. It would
-   involve more kludges, and make the multicast setting code even worse.
-   Instead, just use the ALMUL method.   This is reasonable, considering that
-   it is seldom used
-*/
-		outw( inw( ioaddr + RCR ) & ~RCR_PROMISC, ioaddr + RCR );
-		outw( inw( ioadddr + RCR ) | RCR_ALMUL, ioadddr + RCR );
-	}
-#else
 	else if (dev->mc_count )  {
 		/* support hardware multicasting */
 
@@ -1705,7 +1567,6 @@
 		   last thing called.  The bank is set to zero at the top */
 		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
 	}
-#endif
 	else  {
 		outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
 			ioaddr + RCR );
diff -u --recursive --new-file v2.3.44/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.3.44/linux/drivers/net/strip.c	Tue Nov 23 22:42:21 1999
+++ linux/drivers/net/strip.c	Sat Feb 12 15:45:05 2000
@@ -1036,9 +1036,7 @@
      */
     strip_info->idle_timer.expires = jiffies + 1*HZ;
     add_timer(&strip_info->idle_timer);
-    if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy))
-        printk(KERN_ERR "%s: trying to unlock already unlocked device!\n",
-            strip_info->dev.name);
+    netif_wake_queue(&strip_info->dev);
 }
 
 
@@ -1355,7 +1353,8 @@
     struct strip *strip_info = (struct strip *) tty->disc_data;
 
     /* First make sure we're connected. */
-    if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start)
+    if (!strip_info || strip_info->magic != STRIP_MAGIC || 
+    	!test_bit(LINK_STATE_START, &strip_info->dev.state))
         return;
 
     if (strip_info->tx_left > 0)
@@ -1387,7 +1386,6 @@
     {
         tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
         strip_unlock(strip_info);
-        mark_bh(NET_BH);
     }
 }
 
@@ -1646,12 +1644,14 @@
 {
     struct strip *strip_info = (struct strip *)(dev->priv);
 
-    if (!dev->start)
+    if (!test_bit(LINK_STATE_START, &dev->state))
     {
         printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name);
         return(1);
     }
-    if (test_and_set_bit(0, (void *) &strip_info->dev.tbusy)) return(1);
+
+    netif_stop_queue(dev);
+    
     del_timer(&strip_info->idle_timer);
 
     /* See if someone has been ifconfigging */
@@ -1687,7 +1687,8 @@
 
     strip_send(strip_info, skb);
 
-    if (skb) dev_kfree_skb(skb);
+    if (skb)
+    	dev_kfree_skb(skb);
     return(0);
 }
 
@@ -2336,7 +2337,8 @@
     struct strip *strip_info = (struct strip *) tty->disc_data;
     const unsigned char *end = cp + count;
 
-    if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start)
+    if (!strip_info || strip_info->magic != STRIP_MAGIC 
+    	|| !test_bit(LINK_STATE_START, &strip_info->dev.state))
         return;
 
     /* Argh! mtu change time! - costs us the packet part received at the change */
@@ -2507,13 +2509,11 @@
     if (in_dev->ifa_list->ifa_address == 0)
         in_dev->ifa_list->ifa_address = ntohl(0xC0A80001);
 #endif
-    dev->tbusy  = 0;
-    dev->start  = 1;
-
     printk(KERN_INFO "%s: Initializing Radio.\n", strip_info->dev.name);
     ResetRadio(strip_info);
     strip_info->idle_timer.expires = jiffies + 1*HZ;
     add_timer(&strip_info->idle_timer);
+    netif_wake_queue(dev);
     return(0);
 }
 
@@ -2529,9 +2529,9 @@
     if (strip_info->tty == NULL)
         return -EBUSY;
     strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-    dev->tbusy = 1;
-    dev->start = 0;
 
+    netif_stop_queue(dev);
+    
     /*
      * Free all STRIP frame buffers.
      */
diff -u --recursive --new-file v2.3.44/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.3.44/linux/drivers/net/tulip.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/tulip.c	Sun Feb 13 18:24:53 2000
@@ -102,12 +102,6 @@
 #define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
 #endif
 
-/* This my implementation of shared IRQs, now only used for 1.2.13. */
-#ifdef HAVE_SHARED_IRQ
-#define USE_SHARED_IRQ
-#include <linux/shared_irq.h>
-#endif
-
 /* The total size is unusually large: The 21040 aligns each of its 16
    longword-wide registers on a quadword boundary. */
 #define TULIP_TOTAL_SIZE 0x80
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.3.44/linux/drivers/net/wan/cycx_x25.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/cycx_x25.c	Sun Feb 13 18:20:21 2000
@@ -93,6 +93,9 @@
 /* This is an extension of the 'struct net_device' we create for each network
    interface to keep the rest of X.25 channel-specific data. */
 typedef struct x25_channel {
+	/* This member must be first. */
+	struct net_device *slave;	/* WAN slave */
+
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
 	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
 	char *local_addr;		/* local media address, ASCIIZ -
@@ -502,12 +505,10 @@
 	x25_channel_t *chan = dev->priv;
 	cycx_t *card = chan->card;
 
-	if (dev->start)
+	if (test_bit(LINK_STATE_START, &dev->state))
 		return -EBUSY; /* only one open is allowed */ 
 
-	dev->interrupt = 0;
-	dev->tbusy = 0;
-	dev->start = 1;
+	netif_start_queue(dev);
 	cyclomx_mod_inc_use_count(card);
 
 	return 0;
@@ -521,8 +522,8 @@
 	x25_channel_t *chan = dev->priv;
 	cycx_t *card = chan->card;
 
-	dev->start = 0;
-
+	netif_stop_queue(dev);
+	
 	if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
 		chan_disconnect(dev);
 		
@@ -556,7 +557,7 @@
 }
 
 /* Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
+ * o set busy flag (marks start of the transmission).
  * o check link state. If link is not up, then drop the packet.
  * o check channel status. If it's down then initiate a call.
  * o pass a packet to corresponding WAN device.
@@ -575,11 +576,6 @@
 	x25_channel_t *chan = dev->priv;
 	cycx_t *card = chan->card;
 
-	if (dev->tbusy) {
-		++chan->ifstats.rx_dropped;	
-		return -EBUSY;	
-	}
-
 	if (!chan->svc)
 		chan->protocol = skb->protocol;
 
@@ -595,14 +591,14 @@
 		switch (chan->state) {
 			case WAN_DISCONNECTED:
 				if (chan_connect(dev)) {
-					dev->tbusy = 1;
+					netif_stop_queue(dev);
 					return -EBUSY;
 				}
 				/* fall thru */
 			case WAN_CONNECTED:
 				reset_timer(dev);
 				dev->trans_start = jiffies;
-				dev->tbusy = 1;
+				netif_stop_queue(dev);
 
 				if (chan_send(dev, skb))
 					return -EBUSY;
@@ -632,8 +628,8 @@
 		skb_pull(skb, 1); /* Remove control byte */
 		reset_timer(dev);
 		dev->trans_start = jiffies;
-		dev->tbusy = 1;
-
+		netif_stop_queue(dev);
+		
 		if (chan_send(dev, skb)) {
 			/* prepare for future retransmissions */
 			skb_push(skb, 1);
@@ -705,9 +701,6 @@
 	cycx_poke(&card->hw, 0, &z, sizeof(z));
 	cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));
 	card->in_isr = 0;
-
-	if (card->buff_int_mode_unbusy)
-		mark_bh(NET_BH);
 }
 
 /* Transmit interrupt handler.
@@ -724,7 +717,7 @@
 	/* unbusy device and then dev_tint(); */
 	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
 		card->buff_int_mode_unbusy = 1;
-		dev->tbusy = 0;
+		netif_wake_queue(dev);
 	} else
 		printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n",
 				 card->devname, lcn);
@@ -1263,11 +1256,13 @@
 static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
 {
 	struct net_device *dev = wandev->dev;
+	x25_channel_t *chan;
 
-	for (; dev; dev = dev->slave)
-		if (((x25_channel_t*)dev->priv)->lcn == lcn)
+	while (dev) {
+		if (chan->lcn == lcn)
 			break;
-	
+		dev = chan->slave;
+	}	
 	return dev;
 }
 
@@ -1275,11 +1270,13 @@
 static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
 {
 	struct net_device *dev = wandev->dev;
+	x25_channel_t *chan;
 
-	for (; dev; dev = dev->slave)
-		if (!strcmp(((x25_channel_t*)dev->priv)->addr, dte))
+	while (dev) {
+		if (!strcmp(chan->addr, dte))
 			break;
-
+		dev = chan->slave;
+	}
 	return dev;
 }
 
@@ -1357,7 +1354,7 @@
 			case WAN_CONNECTED:
 				string_state = "connected!";
 				*(u16*)dev->dev_addr = htons(chan->lcn);
-				dev->tbusy = 0;
+				netif_wake_queue(dev);
 				reset_timer(dev);
 
 				if (chan->protocol == ETH_P_X25)
@@ -1384,7 +1381,7 @@
 				if (chan->protocol == ETH_P_X25)
 					chan_x25_send_event(dev, 2);
 
-				dev->tbusy = 0;
+				netif_wake_queue(dev);
 				break;
 		}
 
@@ -1560,15 +1557,16 @@
 	struct net_device *dev = wandev->dev;
 
 	printk(KERN_INFO "X.25 dev states\n");
-	printk(KERN_INFO "name: addr:           tbusy:  protocol:\n");
+	printk(KERN_INFO "name: addr:           txoff:  protocol:\n");
 	printk(KERN_INFO "---------------------------------------\n");
 
-	for (; dev; dev = dev->slave) {
+	while(dev) {
 		x25_channel_t *chan = dev->priv;
 
-		printk(KERN_INFO "%-5.5s %-15.15s   %ld     ETH_P_%s\n",
-				 chan->name, chan->addr, dev->tbusy,
+		printk(KERN_INFO "%-5.5s %-15.15s   %d     ETH_P_%s\n",
+				 chan->name, chan->addr, test_bit(LINK_STATE_XOFF, &dev->state),
 				 chan->protocol == ETH_P_IP ? "IP" : "X25");
+		dev = chan->slave;
 	}
 }
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- v2.3.44/linux/drivers/net/wan/lapbether.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/net/wan/lapbether.c	Sat Feb 12 15:45:05 2000
@@ -163,7 +163,7 @@
 	
 	dev = lapbeth_get_x25_dev(dev);
 
-	if (dev == NULL || dev->start == 0) {
+	if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) {
 		kfree_skb(skb);
 		return 0;
 	}
@@ -215,7 +215,7 @@
 	 * Just to be *really* sure not to send anything if the interface
 	 * is down, the ethernet device may have gone.
 	 */
-	if (!dev->start) {
+	if (!test_bit(LINK_STATE_START, &dev->state)) {
 		lapbeth_check_devices(dev);
 		kfree_skb(skb);
 		return -ENODEV;
@@ -360,9 +360,6 @@
 	if (lapbeth_check_devices(dev))
 		return -ENODEV;		/* oops, it's gone */
 	
-	dev->tbusy = 0;
-	dev->start = 1;
-
 	lapbeth = (struct lapbethdev *)dev->priv;
 
 	lapbeth_callbacks.connect_confirmation    = lapbeth_connected;
@@ -374,12 +371,11 @@
 
 	if ((err = lapb_register(lapbeth, &lapbeth_callbacks)) != LAPB_OK) {
 		printk(KERN_ERR "lapbeth: lapb_register error - %d\n", err);
-		dev->tbusy = 1;
-		dev->start = 0;
 		return -ENODEV;
 	}
 
 	MOD_INC_USE_COUNT;
+	netif_start_queue(dev);
 
 	return 0;
 }
@@ -389,9 +385,8 @@
 	struct lapbethdev *lapbeth;
 	int err;
 
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
+	
 	lapbeth = (struct lapbethdev *)dev->priv;
 
 	if ((err = lapb_unregister(lapbeth)) != LAPB_OK)
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c
--- v2.3.44/linux/drivers/net/wan/sbni.c	Fri Oct 15 15:25:13 1999
+++ linux/drivers/net/wan/sbni.c	Sat Feb 12 15:45:05 2000
@@ -59,11 +59,6 @@
 
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >=0x020200
-#define v22
-#endif
-
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -74,6 +69,7 @@
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/types.h>
@@ -88,12 +84,8 @@
 
 #include <net/arp.h>
 
-
-
-#ifdef v22
 #include <asm/uaccess.h>
 #include <linux/init.h>
-#endif
 
 #include "sbni.h"
 
@@ -523,6 +515,7 @@
 	dev->hard_header_cache = sbni_header_cache;
 	dev->header_cache_update = sbni_header_cache_update;
   
+  	spin_lock_init(&lp->lock);
 	lp->m=dev;
 	lp->me=dev;
 	lp->next_lp=NULL;
@@ -538,15 +531,15 @@
 {
 	struct net_local* lp = (struct net_local*)dev->priv;
 	struct timer_list* watchdog = &lp->watchdog;
-   
+	unsigned long flags;   
       
 	DP( printk("%s: sbni_open\n", dev->name); )
      
+     	save_flags(flags);
 	cli();
 	lp->currframe = NULL;
    
 	card_start(dev);
-	dev->start = 1;
 	/* set timer  watchdog */
 	init_timer(watchdog);
 	watchdog->expires = jiffies + SBNI_TIMEOUT;
@@ -555,8 +548,9 @@
 	add_timer(watchdog);
 	DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
    
-	sti();
-   
+	restore_flags(flags);
+	   
+	netif_start_queue(dev);
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -566,21 +560,18 @@
 	int ioaddr = dev->base_addr;
 	struct net_local* lp = (struct net_local*) dev->priv;
 	struct timer_list* watchdog = &lp->watchdog;
-
-   
+	unsigned long flags;
+	
 	DP( printk("%s: sbni_close\n", dev->name); )
 
+	netif_stop_queue(dev);
+
+	save_flags(flags);
 	cli();
-   
 	sbni_drop_tx_queue(dev);	
-   
-	dev->tbusy = 1;
-	dev->start = 0;
-
 	del_timer(watchdog);
-
 	outb(0, ioaddr + CSR0);
-	sti();
+	restore_flags(flags);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -590,6 +581,7 @@
 {
 	struct net_local *lp = (struct net_local*)dev->priv;
 	struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
+	unsigned long flags;
   
 #ifdef KATYUSHA   
 	struct net_local *nl;
@@ -602,13 +594,6 @@
 	if(lp->me != dev)
 		panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
   
-	if(dev->interrupt)
-	{
-		DP( printk("sbni_xmit_start: interrupt\n"); )
-		/* May be unloading, don't stamp on */	
-		return 1;	/* the packet buffer this time      */
-	}
-  
 	hh->number = 1;
 	hh->reserv = 0;
   
@@ -623,6 +608,7 @@
 		       skb->len - sizeof(struct sbni_hard_header),
 		       hh->crc);
   
+  	spin_lock_irqsave(&lp->lock, flags);
 #ifdef KATYUSHA
 	/* looking for first idle device */
 	for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
@@ -657,6 +643,7 @@
 	/* set request for transmit */
 	outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
 #endif
+	spin_unlock_irqrestore(&lp->lock, flags);
 	return 0;
 }
 
@@ -677,9 +664,6 @@
 	lp->waitack=0;
 	skb_queue_head_init(&lp->queue);
 	sbni_drop_tx_queue(dev);
-	dev->tbusy = 0;
-   
-	dev->interrupt = 0;
 	/* Reset the card and set start parameters */
 	outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
 	outb(EN_INT, dev->base_addr + CSR0);
@@ -776,8 +760,7 @@
 					/*
 	      				 * reset output active flags
 					 */
-					dev->tbusy = 0;
-					mark_bh(NET_BH);
+					netif_wake_queue(dev);
 					/*} if */
 				}
 				case PACKET_RESEND:
@@ -920,17 +903,12 @@
 		return;
 	}
    
-	if(dev->interrupt)
-	{
-		printk("%s: Reentering the interrupt driver!\n", dev->name);
-		return;
-	}
-	dev->interrupt = 1;
-   
 	csr0 = inb(dev->base_addr + CSR0);
 	DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
      
 	lp=dev->priv;
+
+   	spin_lock(&lp->lock);
   
 	if(!lp->carrier)
 		lp->carrier=1;
@@ -971,7 +949,7 @@
 	 */
   
 	outb(csr0 | EN_INT, dev->base_addr + CSR0);
-	dev->interrupt = 0;
+	spin_unlock(&lp->lock);
 }
 
 static struct enet_statistics *sbni_get_stats(struct net_device *dev)
@@ -1103,7 +1081,7 @@
 	}
 	sti();
 	outb(csr0 | RC_CHK, dev->base_addr + CSR0);
-	if(dev->start)
+	if(test_bit(LINK_STATE_START, &dev->state))
 	{
 		struct timer_list* watchdog = &lp->watchdog; 
 		init_timer(watchdog);
@@ -1167,9 +1145,8 @@
 		}
 	}
 	lp->waitack=0;
-  	dev->tbusy = 0;
-  
-	mark_bh(NET_BH);
+	netif_wake_queue(dev);
+	
 	DP( printk("%s: queue dropping stoped\n",dev->name); );	
 }
 
@@ -1194,7 +1171,7 @@
 	/* struct net_local *lp = (struct net_local *)dev->priv; */
 	struct sockaddr *saddr = addr;
 	
-	if(dev->start)
+	if(test_bit(LINK_STATE_START, &dev->state))
 	{
 		/* Only possible while card isn't started */
 		return -EBUSY;
@@ -1400,13 +1377,11 @@
 static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
 static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
 
-#ifdef v22
 MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
 MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
 MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
 MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-#endif
 
 
 static int sbniautodetect = -1;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sbni.h linux/drivers/net/wan/sbni.h
--- v2.3.44/linux/drivers/net/wan/sbni.h	Mon Oct 11 15:38:15 1999
+++ linux/drivers/net/wan/sbni.h	Sat Feb 12 15:45:05 2000
@@ -146,7 +146,7 @@
 
 	int carrier;
 
-
+	spinlock_t lock;
 };
 
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- v2.3.44/linux/drivers/net/wan/sdla_chdlc.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/sdla_chdlc.c	Sun Feb 13 18:20:21 2000
@@ -74,6 +74,9 @@
 
 typedef struct chdlc_private_area
 {
+	/* This member must be first. */
+	struct net_device *slave;		/* WAN slave */
+
 	sdla_t		*card;
 	int 		TracingEnabled;		/* For enabling Tracing */
 	unsigned long 	curr_trace_addr;	/* Used for Tracing */
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.3.44/linux/drivers/net/wan/sdla_fr.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/sdla_fr.c	Sun Feb 13 18:20:21 2000
@@ -167,6 +167,9 @@
  */
 typedef struct fr_channel
 {
+	/* This member must be first. */
+	struct net_device *slave;	/* WAN slave */
+
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
 	unsigned dlci_configured  ;	/* check whether configured or not */
 	unsigned cir_status;		/* check whether CIR enabled or not */
@@ -1960,7 +1963,9 @@
 	// Used to send inarp request at given interval 
 	if (card->wandev.state == WAN_CONNECTED) {
         	int num_remaining = 0;
-                for (dev=card->wandev.dev;dev;dev=dev->slave) {
+
+		dev = card->wandev.dev;
+		while (dev) {
                 	fr_channel_t *chan = dev->priv;
 
                         if (chan->inarp == INARP_REQUEST &&
@@ -1972,6 +1977,7 @@
                                 	chan->inarp_tick = jiffies;
                                 }
 			}
+			dev = chan->slave;
 		}
 		if (!num_remaining) {   // no more to process 
                         flags->imask &= ~FR_INTR_TIMER;
@@ -2135,65 +2141,68 @@
 
 
 	/* Dynamic Route adding/removing */
-	for (dev = card->wandev.dev; dev ; dev = dev->slave) {
-	     if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE   ||
-		((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) {
-		fs = get_fs();
+	dev = card->wandev.dev;
+	while (dev) {
+		fr_channel_t *chan = dev->priv;
+
+		if (chan->route_flag == ADD_ROUTE   ||
+		    chan->route_flag == REMOVE_ROUTE ) {
+			fs = get_fs();
 		
-		in_dev = dev->ip_ptr;
+			in_dev = dev->ip_ptr;
 
-		if( in_dev != NULL && in_dev->ifa_list != NULL) {
-			memset(&route, 0, sizeof(route));
-			route.rt_dev   = dev->name;
-			route.rt_flags = 0;
-
-			((struct sockaddr_in *) &(route.rt_dst)) ->
-				sin_addr.s_addr=in_dev->ifa_list->ifa_address;
-			((struct sockaddr_in *) &(route.rt_dst)) ->
-				sin_family = AF_INET;
-			((struct sockaddr_in *) &(route.rt_genmask)) ->
-				sin_addr.s_addr = 0xFFFFFFFF;
-			((struct sockaddr_in *) &(route.rt_genmask)) ->
-				sin_family = AF_INET;
-
-			switch(((fr_channel_t*)dev->priv)->route_flag) {
-
-			case ADD_ROUTE:
-				set_fs(get_ds());     /* get user space block */
-				err = ip_rt_ioctl( SIOCADDRT, &route);	
-				set_fs(fs);	      /* restore old block */
-
-				if (err) {
-					printk(KERN_INFO "%s: Adding of route failed.  Error: %d\n", card->devname,err);
-					printk(KERN_INFO "%s: Address: %s\n",
-					((fr_channel_t*)dev->priv)->name,
-					in_ntoa(in_dev->ifa_list->ifa_address) );
-				}
-				else {
-					((fr_channel_t*)dev->priv)->
-						route_flag = ROUTE_ADDED;
-				}
-				break;
+			if( in_dev != NULL && in_dev->ifa_list != NULL) {
+				memset(&route, 0, sizeof(route));
+				route.rt_dev   = dev->name;
+				route.rt_flags = 0;
+
+				((struct sockaddr_in *) &(route.rt_dst)) ->
+					sin_addr.s_addr=in_dev->ifa_list->ifa_address;
+				((struct sockaddr_in *) &(route.rt_dst)) ->
+					sin_family = AF_INET;
+				((struct sockaddr_in *) &(route.rt_genmask)) ->
+					sin_addr.s_addr = 0xFFFFFFFF;
+				((struct sockaddr_in *) &(route.rt_genmask)) ->
+					sin_family = AF_INET;
+
+				switch(chan->route_flag) {
+
+				case ADD_ROUTE:
+					set_fs(get_ds());     /* get user space block */
+					err = ip_rt_ioctl( SIOCADDRT, &route);	
+					set_fs(fs);	      /* restore old block */
+
+					if (err) {
+						printk(KERN_INFO "%s: Adding of route failed.  Error: %d\n", card->devname,err);
+						printk(KERN_INFO "%s: Address: %s\n",
+						       chan->name,
+						       in_ntoa(in_dev->ifa_list->ifa_address) );
+					} else {
+						chan->route_flag = ROUTE_ADDED;
+					}
+					break;
 
-			case REMOVE_ROUTE:
-				set_fs(get_ds());     /* get user space block */
-				err = ip_rt_ioctl( SIOCDELRT, &route);
-				set_fs(fs);	      /* restore old block */
-
-				if (err) {
-			     		printk(KERN_INFO "%s: Deleting of route failed.  Error: %d\n", card->devname,err);
-			    		printk(KERN_INFO "%s: Address: %s\n",
-					dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
-				} else {
-			    	 	printk(KERN_INFO "%s: Removed route.\n",
-					((fr_channel_t*)dev->priv)->name);
-			     		((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE;
-				}
-				break;
-			} /* Case Statement */
-		}
-	     } /* If ADD/DELETE ROUTE */
-	}  /* Device 'For' Loop */
+				case REMOVE_ROUTE:
+					set_fs(get_ds());     /* get user space block */
+					err = ip_rt_ioctl( SIOCDELRT, &route);
+					set_fs(fs);	      /* restore old block */
+
+					if (err) {
+						printk(KERN_INFO "%s: Deleting of route failed.  Error: %d\n", card->devname,err);
+						printk(KERN_INFO "%s: Address: %s\n",
+						       dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
+					} else {
+						printk(KERN_INFO "%s: Removed route.\n",
+						       chan->name);
+						chan->route_flag = NO_ROUTE;
+					}
+					break;
+				} /* Case Statement */
+			}
+		} /* If ADD/DELETE ROUTE */
+
+		dev = chan->slave;
+	}  /* Device 'While' Loop */
 
 	card->poll = NULL;
 }
@@ -2568,7 +2577,8 @@
 			struct net_device *dev;
 
 			/* Remove all routes from associated DLCI's */
-			for (dev = card->wandev.dev; dev; dev = dev->slave) {
+			dev = card->wandev.dev;
+			while (dev) {
 				fr_channel_t *chan = dev->priv;
 				if (chan->route_flag == ROUTE_ADDED) {
 					chan->route_flag = REMOVE_ROUTE;
@@ -2578,6 +2588,8 @@
 				if (chan->inarp == INARP_CONFIGURED) {
 					chan->inarp = INARP_REQUEST;
 				}
+
+				dev = chan->slave;
 			}
 
 			wanpipe_set_state(card, WAN_DISCONNECTED);
@@ -2590,12 +2602,14 @@
 			int num_requests = 0;
 
 			/* Remove all routes from associated DLCI's */
-			for (dev = card->wandev.dev; dev; dev = dev->slave) {
+			dev = card->wandev.dev;
+			while (dev) {
 				fr_channel_t *chan = dev->priv;	
 				if( chan->inarp == INARP_REQUEST ){
 					num_requests++;
 					chan->inarp_tick = jiffies;
 				}
+				dev = chan->slave;
 			}
 
 			/* Allow timer interrupts */
@@ -2731,8 +2745,8 @@
 		}
 	}
 	
-	for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){
-		
+	dev2 = card->wandev.dev;
+	while (dev2) {
 		chan = dev2->priv;
 	
 		if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
@@ -2741,6 +2755,7 @@
 			}
 		}
 
+		dev2 = chan->slave;
 	}
 	return 1;
 }
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- v2.3.44/linux/drivers/net/wan/sdla_ppp.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/wan/sdla_ppp.c	Sun Feb 13 18:20:21 2000
@@ -155,6 +155,9 @@
   
 typedef struct ppp_private_area
 {
+	/* This member must be first. */
+	struct net_device *slave;	/* WAN slave */
+
 	sdla_t* card;	
 	unsigned long router_start_time;	/*router start time in sec */
 	unsigned long tick_counter;		/*used for 5 second counter*/
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- v2.3.44/linux/drivers/net/wan/sdla_x25.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/net/wan/sdla_x25.c	Sun Feb 13 18:20:21 2000
@@ -75,6 +75,9 @@
  */
 typedef struct x25_channel
 {
+	/* This member must be first. */
+	struct net_device *slave;	/* WAN slave */
+
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
 	char addr[WAN_ADDRESS_SZ+1];	/* media address, ASCIIZ */
 	unsigned lcn;			/* logical channel number */
@@ -708,11 +711,13 @@
 			return dev->tbusy;
 		}
 		printk(KERN_INFO "%s: Transmit time out %s!\n",
-			card->devname, dev->name)
-		;
-		for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
-		{
+		       card->devname, dev->name);
+
+		dev2 = card->wandev.dev;
+		while (dev2) {
+			x25_channel_t *chan2 = dev2->priv;
 	        	dev2->tbusy = 0;
+			dev2 = chan2->slave;
 		}
 	}
 	chan->tick_counter = jiffies;
@@ -898,13 +903,17 @@
 
 	if(card->buff_int_mode_unbusy)
 	{
-		for(dev = card->wandev.dev; dev; dev = dev->slave)
-		{
-			if(((x25_channel_t*)dev->priv)->devtint)
-			{
+		x25_channel_t *chan;
+
+		dev = card->wandev.dev;
+		while (dev) {
+			chan = dev->priv;
+			if(chan->devtint) {
 				mark_bh(NET_BH);
 				return;
 			}	
+
+			dev = chan->slave;
 		}
 	}
 }
@@ -1042,12 +1051,15 @@
 static void tx_intr (sdla_t* card)
 {
 	struct net_device *dev;
+	x25_channel_t *chan;
 
 	/* unbusy all devices and then dev_tint(); */
-	for(dev = card->wandev.dev; dev; dev = dev->slave)
-	{
-		((x25_channel_t*)dev->priv)->devtint = dev->tbusy; 
+	dev = card->wandev.dev;
+	while (dev) {
+		chan->devtint = dev->tbusy; 
 		dev->tbusy = 0;
+
+		dev = chan->slave;
 	}
 
 }
@@ -1170,8 +1182,8 @@
 	/* Fetch X.25 asynchronous events */
 	x25_fetch_events(card);
 
-	for (dev = card->wandev.dev; dev; dev = dev->slave)
-	{
+	dev = card->wandev.dev;
+	while (dev) {
 		x25_channel_t* chan = dev->priv;
 		struct sk_buff* skb = chan->tx_skb;
 
@@ -1199,6 +1211,8 @@
 				chan_disc(dev);
 			}
 		}
+
+		dev = chan->slave;
 	}
 }
 
@@ -1785,8 +1799,8 @@
 		card->devname, new_lcn, mb->data);
 
 	/* Find available channel */
-	for (dev = wandev->dev; dev; dev = dev->slave)
-	{
+	dev = wandev->dev;
+	while (dev) {
 		chan = dev->priv;
 
 		if (!chan->svc || (chan->state != WAN_DISCONNECTED))
@@ -1796,6 +1810,8 @@
 	        /* If just an '@' is specified, accept all incoming calls */
 	        if (strcmp(chan->addr, "") == 0)
 	                break;
+
+		dev = chan->slave;
 	}
 
 	if (dev == NULL)
@@ -1912,8 +1928,14 @@
 		card->devname, mb->cmd.cause, mb->cmd.diagn);
 
 	/* down all logical channels */
-	for (dev = wandev->dev; dev; dev = dev->slave)
+	dev = wandev->dev;
+	while (dev) {
+		x25_channel_t *chan = dev->priv;
+
 		set_chan_state(dev, WAN_DISCONNECTED);
+		dev = chan->slave;
+	}
+
 	return (cmd == X25_WRITE) ? 0 : 1;
 }
 
@@ -1979,10 +2001,14 @@
 static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
 {
 	struct net_device* dev;
+	x25_channel_t *chan;
 
-	for (dev = wandev->dev; dev; dev = dev->slave)
-		if (((x25_channel_t*)dev->priv)->lcn == lcn)
+	dev = wandev->dev;
+	while (dev) {
+		if (chan->lcn == lcn)
 			break;
+		dev = chan->slave;
+	}
 	return dev;
 }
 
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- v2.3.44/linux/drivers/net/wan/x25_asy.c	Thu Nov 11 20:11:42 1999
+++ linux/drivers/net/wan/x25_asy.c	Sat Feb 12 15:45:05 2000
@@ -205,8 +205,7 @@
 
 static inline void x25_asy_lock(struct x25_asy *sl)
 {
-	if (test_and_set_bit(0, (void *) &sl->dev->tbusy))
-		printk("%s: trying to lock already locked device!\n", sl->dev->name);
+	netif_stop_queue(sl->dev);
 }
 
 
@@ -214,8 +213,7 @@
 
 static inline void x25_asy_unlock(struct x25_asy *sl)
 {
-	if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy))
-		printk("%s: trying to unlock already unlocked device!\n", sl->dev->name);
+	netif_wake_queue(sl->dev);
 }
 
 /* Send one completely decapsulated IP datagram to the IP layer. */
@@ -303,7 +301,7 @@
 	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
 
 	/* First make sure we're connected. */
-	if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
+	if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state))
 		return;
 
 	if (sl->xleft <= 0)  
@@ -313,7 +311,6 @@
 		sl->tx_packets++;
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 		x25_asy_unlock(sl);
-		mark_bh(NET_BH);
 		return;
 	}
 
@@ -322,6 +319,20 @@
 	sl->xhead += actual;
 }
 
+static void x25_asy_timeout(struct net_device *dev)
+{
+	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+	/* May be we must check transmitter timeout here ?
+	 *      14 Oct 1994 Dmitry Gorodchanin.
+	 */
+	printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+	       (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
+	       "bad line quality" : "driver error");
+	sl->xleft = 0;
+	sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	x25_asy_unlock(sl);
+}
+
 /* Encapsulate an IP datagram and kick it into a TTY queue. */
 
 static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -329,7 +340,7 @@
 	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
 	int err;
 
-	if (!dev->start)  
+	if (!test_bit(LINK_STATE_START, &sl->dev->state))
 	{
 		printk("%s: xmit call when iface is down\n", dev->name);
 		return 1;
@@ -361,25 +372,6 @@
 	 * So, no queues !
 	 *        14 Oct 1994  Dmitry Gorodchanin.
 	 */
-	if (dev->tbusy) {
-		/* May be we must check transmitter timeout here ?
-		 *      14 Oct 1994 Dmitry Gorodchanin.
-		 */
-#ifdef SL_CHECK_TRANSMIT
-		if (jiffies - dev->trans_start  < 20 * HZ)  {
-			/* 20 sec timeout not reached */
-			return 1;
-		}
-		printk("%s: transmit timed out, %s?\n", dev->name,
-		       (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ?
-		       "bad line quality" : "driver error");
-		sl->xleft = 0;
-		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-		x25_asy_unlock(sl);
-#else
-		return 1;
-#endif
-	}
 	
 	if((err=lapb_data_request(sl,skb))!=LAPB_OK)
 	{
@@ -414,7 +406,7 @@
 static void x25_asy_data_transmit(void *token, struct sk_buff *skb)
 {
 	struct x25_asy *sl=token;
-	if(sl->dev->tbusy)
+	if(test_bit(LINK_STATE_XOFF, &sl->dev->state))
 	{
 		printk(KERN_ERR "x25_asy: tbusy drop\n");
 		kfree_skb(skb);
@@ -514,10 +506,8 @@
 	sl->xleft    = 0;
 	sl->flags   &= (1 << SLF_INUSE);      /* Clear ESCAPE & ERROR flags */
 
-	dev->tbusy  = 0;
-/*	dev->flags |= IFF_UP; */
-	dev->start  = 1;
-	
+	netif_start_queue(dev);
+			
 	/*
 	 *	Now attach LAPB
 	 */
@@ -551,12 +541,9 @@
 		return -EBUSY;
 
 	sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-	dev->tbusy = 1;
-	dev->start = 0;
+	netif_stop_queue(dev);
 	if((err=lapb_unregister(sl))!=LAPB_OK)
 		printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
-
-/*	dev->flags &= ~IFF_UP; */
 	return 0;
 }
 
@@ -576,7 +563,7 @@
 {
 	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
 
-	if (!sl || sl->magic != X25_ASY_MAGIC || !sl->dev->start)
+	if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state))
 		return;
 
 	/*
@@ -876,6 +863,8 @@
 	 
 	dev->mtu		= SL_MTU;
 	dev->hard_start_xmit	= x25_asy_xmit;
+	dev->tx_timeout		= x25_asy_timeout;
+	dev->watchdog_timeo	= HZ*20;
 	dev->open		= x25_asy_open_dev;
 	dev->stop		= x25_asy_close;
 	dev->get_stats	        = x25_asy_get_stats;
@@ -914,7 +903,7 @@
 				 * VSV = if dev->start==0, then device
 				 * unregistered while close proc.
 				 */
-				if (x25_asy_ctrls[i]->dev.start)
+				if (test_bit(LINK_STATE_START, &x25_asy_ctrls[i]->dev.state))
 					unregister_netdev(&(x25_asy_ctrls[i]->dev));
 
 				kfree(x25_asy_ctrls[i]);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c
--- v2.3.44/linux/drivers/net/wan/z85230.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/net/wan/z85230.c	Sat Feb 12 15:45:05 2000
@@ -54,12 +54,23 @@
 
 static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
 
-/*
+/**
+ *	z8530_read_port:
+ *	@p: port to read
+ *
  *	Provided port access methods. The Comtrol SV11 requires no delays
  *	between accesses and uses PC I/O. Some drivers may need a 5uS delay
+ *	
+ *	In the longer term this should become an architecture specific
+ *	section so that this can become a generic driver interface for all
+ *	platforms. For now we only handle PC I/O ports with or without the
+ *	dread 5uS sanity delay.
+ *
+ *	The caller must hold sufficient locks to avoid violating the horrible
+ *	5uS delay rule.
  */
 
-extern __inline__ int z8530_read_port(int p)
+extern __inline__ int z8530_read_port(unsigned long p)
 {
 	u8 r=inb(Z8530_PORT_OF(p));
 	if(p&Z8530_PORT_SLEEP)	/* gcc should figure this out efficiently ! */
@@ -67,7 +78,23 @@
 	return r;
 }
 
-extern __inline__ void z8530_write_port(int p, u8 d)
+/**
+ *	z8530_write_port:
+ *	@p: port to write
+ *	@d: value to write
+ *
+ *	Write a value to a port with delays if need be. Note that the
+ *	caller must hold locks to avoid read/writes from other contexts
+ *	violating the 5uS rule
+ *
+ *	In the longer term this should become an architecture specific
+ *	section so that this can become a generic driver interface for all
+ *	platforms. For now we only handle PC I/O ports with or without the
+ *	dread 5uS sanity delay.
+ */
+
+
+extern __inline__ void z8530_write_port(unsigned long p, u8 d)
 {
 	outb(d,Z8530_PORT_OF(p));
 	if(p&Z8530_PORT_SLEEP)
@@ -80,8 +107,16 @@
 static void z8530_tx_done(struct z8530_channel *c);
 
 
-/*
- *	Port accesses
+/**
+ *	read_zsreg:
+ *	@c: Z8530 channel to read from (2 per chip)
+ *	@reg: Register to read
+ *	FIXME: Use a spinlock.
+ *	
+ *	Most of the Z8530 registers are indexed off the control registers.
+ *	A read is done by writing to the control register and reading the
+ *	register back. We do the locking needed to protect this 
+ *	operation.
  */
  
 extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
@@ -97,6 +132,14 @@
 	return r;
 }
 
+/**
+ *	read_zsdata:
+ *	@c: The Z8530 channel to read the data port from
+ *
+ *	The data port provides fast access to some things. We still
+ *	have all the 5uS delays to worry about.
+ */
+
 extern inline u8 read_zsdata(struct z8530_channel *c)
 {
 	u8 r;
@@ -104,6 +147,17 @@
 	return r;
 }
 
+/**
+ *	write_zsreg:
+ *	@c: The Z8530 channel
+ *	@reg: Register number
+ *	@val: Value to write
+ *
+ *	Write a value to an indexed register. Perform the locking needed
+ *	to honour the irritating delay rules. We know about register 0
+ *	being fast to access.
+ */
+ 
 extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
 {
 	unsigned long flags;
@@ -194,8 +248,16 @@
 
 EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
 
-/*
- *	Flush the FIFO
+/**
+ *	z8530_flush_fifo:
+ *	@c: Channel to flush
+ *
+ *	Flush the receive FIFO. There is no specific option for this, we 
+ *	blindly read bytes and discard them. Reading when there is no data
+ *	is harmless. The 8530 has a 4 byte FIFO, the 85230 has 8 bytes.
+ *	
+ *	All locking is handled for the caller. On return data may still be
+ *	present if it arrived during the flush.
  */
  
 static void z8530_flush_fifo(struct z8530_channel *c)
@@ -213,7 +275,16 @@
 	}
 }	
 
-/* Sets or clears DTR/RTS on the requested line */
+/**
+ *	z8530_rtsdtr:
+ *	@c: The Z8530 channel to contro;
+ *	@set: 1 to set, 0 to clear
+ *
+ *	Sets or clears DTR/RTS on the requested line. All locking is handled
+ *	for the caller. For now we assume all boards use the actual RTS/DTR
+ *	on the chip. Apparently one or two don't. We'll scream about them
+ *	later.
+ */
 
 static void z8530_rtsdtr(struct z8530_channel *c, int set)
 {
@@ -224,9 +295,12 @@
 	write_zsreg(c, R5, c->regs[5]);
 }
 
-/*
- *	Receive handler. This is much like the async one but not quite the
- *	same or as complex
+/**
+ *	z8530_rx:
+ *	@c: Z8530 channel to process
+ *
+ *	Receive handler for receiving in PIO mode. This is much like the 
+ *	async one but not quite the same or as complex
  *
  *	Note: Its intended that this handler can easily be separated from
  *	the main code to run realtime. That'll be needed for some machines
@@ -238,9 +312,9 @@
  *	other code - this is true in the RT case too.
  *
  *	We only cover the sync cases for this. If you want 2Mbit async
- *	do it yourself but consider medical assistance first.
- *
- *	This non DMA synchronous mode is portable code.
+ *	do it yourself but consider medical assistance first. This non DMA 
+ *	synchronous mode is portable code. The DMA mode assumes PCI like 
+ *	ISA DMA
  */
  
 static void z8530_rx(struct z8530_channel *c)
@@ -303,8 +377,14 @@
 }
 
 
-/*
- *	Z8530 transmit interrupt handler
+/**
+ *	z8530_tx:
+ *	@c: Z8530 channel to process
+ *
+ *	Z8530 transmit interrupt handler for the PIO mode. The basic
+ *	idea is to attempt to keep the FIFO fed. We fill as many bytes
+ *	in as possible, its quite possible that we won't keep up with the
+ *	data rate otherwise.
  */
  
 static void z8530_tx(struct z8530_channel *c)
@@ -340,6 +420,17 @@
 	write_zsctrl(c, RES_H_IUS);
 }
 
+/**
+ *	z8530_status:
+ *	@chan: Z8530 channel to process
+ *
+ *	A status event occured in PIO synchronous mode. There are several
+ *	reasons the chip will bother us here. A transmit underrun means we
+ *	failed to feed the chip fast enough and just broke a packet. A DCD
+ *	change is a line up or down. We communicate that back to the protocol
+ *	layer for synchronous PPP to renegotiate.
+ */
+
 static void z8530_status(struct z8530_channel *chan)
 {
 	u8 status=read_zsreg(chan, R0);
@@ -387,9 +478,14 @@
 
 EXPORT_SYMBOL(z8530_sync);
 
-/*
+/**
+ *	z8530_dma_rx:
+ *	@chan: Channel to handle
+ *
  *	Non bus mastering DMA interfaces for the Z8x30 devices. This
- *	is really pretty PC specific.
+ *	is really pretty PC specific. The DMA mode means that most receive
+ *	events are handled by the DMA hardware. We get a kick here only if
+ *	a frame ended.
  */
  
 static void z8530_dma_rx(struct z8530_channel *chan)
@@ -417,6 +513,14 @@
 	}	
 }
 
+/**
+ *	z8530_dma_tx:
+ *	@chan:	The Z8530 channel to handle
+ *
+ *	We have received an interrupt while doing DMA transmissions. It
+ *	shouldn't happen. Scream loudly if it does.
+ */
+ 
 static void z8530_dma_tx(struct z8530_channel *chan)
 {
 	if(!chan->dma_tx)
@@ -430,6 +534,17 @@
 	z8530_tx(chan);
 }
 
+/**
+ *	z8530_dma_status:
+ *	@chan: Z8530 channel to process
+ *	
+ *	A status event occured on the Z8530. We receive these for two reasons
+ *	when in DMA mode. Firstly if we finished a packet transfer we get one
+ *	and kick the next packet out. Secondly we may see a DCD change and
+ *	have to poke the protocol layer.
+ *
+ */
+ 
 static void z8530_dma_status(struct z8530_channel *chan)
 {
 	unsigned long flags;
@@ -490,8 +605,11 @@
 
 EXPORT_SYMBOL(z8530_txdma_sync);
 
-/*
- *	Interrupt vectors for a Z8530 that is in 'parked' mode.
+/**
+ *	z8530_rx_clear:
+ *	@c: Z8530 channel to shut up
+ *
+ *	Receive interrupt vectors for a Z8530 that is in 'parked' mode.
  *	For machines with PCI Z85x30 cards, or level triggered interrupts
  *	(eg the MacII) we must clear the interrupt cause or die.
  */
@@ -516,12 +634,30 @@
 	write_zsctrl(c, RES_H_IUS);
 }
 
+/**
+ *	z8530_tx_clear:
+ *	@c: Z8530 channel to shut up
+ *
+ *	Transmit interrupt vectors for a Z8530 that is in 'parked' mode.
+ *	For machines with PCI Z85x30 cards, or level triggered interrupts
+ *	(eg the MacII) we must clear the interrupt cause or die.
+ */
+
 static void z8530_tx_clear(struct z8530_channel *c)
 {
 	write_zsctrl(c, RES_Tx_P);
 	write_zsctrl(c, RES_H_IUS);
 }
 
+/**
+ *	z8530_status_clear:
+ *	@chan: Z8530 channel to shut up
+ *
+ *	Status interrupt vectors for a Z8530 that is in 'parked' mode.
+ *	For machines with PCI Z85x30 cards, or level triggered interrupts
+ *	(eg the MacII) we must clear the interrupt cause or die.
+ */
+
 static void z8530_status_clear(struct z8530_channel *chan)
 {
 	u8 status=read_zsreg(chan, R0);
@@ -541,8 +677,17 @@
 
 EXPORT_SYMBOL(z8530_nop);
 
-/*
- *	A Z85[2]30 device has stuck its hand in the air for attention
+/**
+ *	z8530_interrupt:
+ *	@irq: 	Interrupt number
+ *	@dev_id: The Z8530 device that is interrupting.
+ *	@regs: unused
+ *
+ *	A Z85[2]30 device has stuck its hand in the air for attention.
+ *	We scan both the channels on the chip for events and then call
+ *	the channel specific call backs for each channel that has events.
+ *	We have to use callback functions because the two channels can be
+ *	in different modes.
  */
 
 void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -612,6 +757,15 @@
 };
 
 
+/**
+ *	z8530_sync_open:
+ *	@dev:	The network interface we are using
+ *	@c:	The Z8530 channel to open in synchronous PIO mode
+ *
+ *	Switch a Z8530 into synchronous mode without DMA assist. We
+ *	raise the RTS/DTR and commence network operation.
+ */
+ 
 int z8530_sync_open(struct net_device *dev, struct z8530_channel *c)
 {
 	c->sync = 1;
@@ -634,6 +788,15 @@
 
 EXPORT_SYMBOL(z8530_sync_open);
 
+/**
+ *	z8530_sync_close:
+ *	@dev: Network device to close
+ *	@c: Z8530 channel to disassociate and move to idle
+ *
+ *	Close down a Z8530 interface and switch its interrupt handlers
+ *	to discard future events.
+ */
+ 
 int z8530_sync_close(struct net_device *dev, struct z8530_channel *c)
 {
 	u8 chk;
@@ -650,6 +813,16 @@
 
 EXPORT_SYMBOL(z8530_sync_close);
 
+/**
+ *	z8530_sync_dma_open:
+ *	@dev: The network device to attach
+ *	@c: The Z8530 channel to configure in sync DMA mode.
+ *
+ *	Set up a Z85x30 device for synchronous DMA in both directions. Two
+ *	ISA DMA channels must be available for this to work. We assume ISA
+ *	DMA driven I/O and PC limits on access.
+ */
+ 
 int z8530_sync_dma_open(struct net_device *dev, struct z8530_channel *c)
 {
 	unsigned long flags;
@@ -760,6 +933,15 @@
 
 EXPORT_SYMBOL(z8530_sync_dma_open);
 
+/**
+ *	z8530_sync_dma_close:
+ *	@dev: Network device to detach
+ *	@c: Z8530 channel to move into discard mode
+ *
+ *	Shut down a DMA mode synchronous interface. Halt the DMA, and
+ *	free the buffers.
+ */
+ 
 int z8530_sync_dma_close(struct net_device *dev, struct z8530_channel *c)
 {
 	u8 chk;
@@ -816,6 +998,16 @@
 
 EXPORT_SYMBOL(z8530_sync_dma_close);
 
+/**
+ *	z8530_sync_txdma_open:
+ *	@dev: The network device to attach
+ *	@c: The Z8530 channel to configure in sync DMA mode.
+ *
+ *	Set up a Z85x30 device for synchronous DMA tranmission. One
+ *	ISA DMA channel must be available for this to work. The receive
+ *	side is run in PIO mode, but then it has the bigger FIFO.
+ */
+
 int z8530_sync_txdma_open(struct net_device *dev, struct z8530_channel *c)
 {
 	unsigned long flags;
@@ -905,7 +1097,16 @@
 }
 
 EXPORT_SYMBOL(z8530_sync_txdma_open);
-	
+
+/**
+ *	z8530_sync_txdma_close:
+ *	@dev: Network device to detach
+ *	@c: Z8530 channel to move into discard mode
+ *
+ *	Shut down a DMA/PIO split mode synchronous interface. Halt the DMA, 
+ *	and  free the buffers.
+ */
+
 int z8530_sync_txdma_close(struct net_device *dev, struct z8530_channel *c)
 {
 	unsigned long flags;
@@ -954,21 +1155,32 @@
 
 EXPORT_SYMBOL(z8530_sync_txdma_close);
 
+
 /*
- *	Describe a Z8530 in a standard format. We must pass the I/O as
- *	the port offset isnt predictable. The main reason for this function
- *	is to try and get a common format of report.
+ *	Name strings for Z8530 chips. SGI claim to have a 130, Zilog deny
+ *	it exists...
  */
-
+ 
 static char *z8530_type_name[]={
 	"Z8530",
 	"Z85C30",
 	"Z85230"
 };
 
-void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
+/**
+ *	z8530_describe:
+ *	@dev: Z8530 device to describe
+ *	@mapping: string holding mapping type (eg "I/O" or "Mem")
+ *	@io: the port value in question
+ *
+ *	Describe a Z8530 in a standard format. We must pass the I/O as
+ *	the port offset isnt predictable. The main reason for this function
+ *	is to try and get a common format of report.
+ */
+
+void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io)
 {
-	printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",
+	printk(KERN_INFO "%s: %s found at %s 0x%lX, IRQ %d.\n",
 		dev->name, 
 		z8530_type_name[dev->type],
 		mapping,
@@ -978,8 +1190,21 @@
 
 EXPORT_SYMBOL(z8530_describe);
 
-/*
- *	Configure up a Z8530
+/**
+ *	z8530_init:
+ *	@dev: Z8530 device to initialise.
+ *
+ *	Configure up a Z8530/Z85C30 or Z85230 chip. We check the device
+ *	is present, identify the type and then program it to hopefully
+ *	keep quite and behave. This matters a lot, a Z8530 in the wrong
+ *	state will sometimes get into stupid modes generating 10Khz
+ *	interrupt streams and the like.
+ *
+ *	We set the interrupt handler up to discard any events, in case
+ *	we get them during reset or setp.
+ *
+ *	Return 0 for success, or a negative value indicating the problem
+ *	in errno form.
  */
 
  
@@ -1047,6 +1272,15 @@
 
 EXPORT_SYMBOL(z8530_init);
 
+/**
+ *	z8530_shutdown:
+ *	@dev: The Z8530 chip to shutdown
+ *
+ *	We set the interrupt handlers to silence any interrupts. We then 
+ *	reset the chip and wait 100uS to be sure the reset completed. Just
+ *	in case the caller then tries to do stuff.
+ */
+ 
 int z8530_shutdown(struct z8530_dev *dev)
 {
 	/* Reset the chip */
@@ -1059,9 +1293,15 @@
 
 EXPORT_SYMBOL(z8530_shutdown);
 
-/*
- *	Load a Z8530 channel up from the system data
- *	We use +16 to indicate the 'prime' registers
+/**
+ *	z8530_channel_load:
+ *	@c: Z8530 channel to configure
+ *	@rtable: Table of register, value pairs
+ *	FIXME: ioctl to allow user uploaded tables
+ *
+ *	Load a Z8530 channel up from the system data> We use +16 to 
+ *	indicate the 'prime' registers. The value 255 terminates the
+ *	table
  */
 
 int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
@@ -1092,8 +1332,16 @@
 EXPORT_SYMBOL(z8530_channel_load);
 
 
-/*
- *	Higher level shovelling - transmit chains
+/**
+ *	z8530_tx_begin:
+ *	@c: The Z8530 channel to kick
+ *
+ *	This is the speed sensitive side of transmission. If we are called
+ *	and no buffer is being transmitted we commence the next buffer. If
+ *	nothing is queued we idle the sync. 
+ *
+ *	Note: We are handling this code path in the interrupt path, keep it
+ *	fast or bad things will happen.
  */
 
 static void z8530_tx_begin(struct z8530_channel *c)
@@ -1180,7 +1428,15 @@
 		}
 	}
 }
- 
+
+/**
+ *	z8530_tx_done:
+ *	@c: The channel that completed a transmit.
+ *
+ *	This is called when we complete a packet send. We wake the queue,
+ *	start the next packet going and then free the buffer of the existing
+ *	packet. This code is fairly timing sensitive.
+ */ 
  
 static void z8530_tx_done(struct z8530_channel *c)
 {
@@ -1201,11 +1457,16 @@
 	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
 	c->stats.tx_packets++;
 	c->stats.tx_bytes+=skb->len;
-	dev_kfree_skb(skb);
+	dev_kfree_skb_irq(skb);
 }
 
-/*
- *	Higher level shovelling - receive chains
+/**
+ *	z8530_null_rx:
+ *	@c: The channel the packet arrived on
+ *	@skb: The buffer
+ *
+ *	We point the receive handler at this function when idle. Instead
+ *	of syncppp processing the frames we get to throw them away.
  */
  
 void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
@@ -1215,6 +1476,17 @@
 
 EXPORT_SYMBOL(z8530_null_rx);
 
+/**
+ *	z8530_rx_done:
+ *	@c: The channel that completed a receive
+ *
+ *	A new packet is complete. Our goal here is to get back into receive
+ *	mode as fast as possible. On the Z85230 we could change to using
+ *	ESCC mode, but on the older chips we have no choice. We flip to the
+ *	new buffer immediately in DMA mode so that the DMA of the next
+ *	frame can occur while we are copying the previous buffer to an sk_buff
+ */
+ 
 static void z8530_rx_done(struct z8530_channel *c)
 {
 	struct sk_buff *skb;
@@ -1269,7 +1541,7 @@
 		else
 			/* Can't occur as we dont reenable the DMA irq until
 			   after the flip is done */
-			printk("DMA flip overrun!\n");
+			printk(KERN_WARNING "%s: DMA flip overrun!\n", c->netdevice->name);
 			
 		release_dma_lock(flags);
 		
@@ -1357,8 +1629,12 @@
 	}
 }
 
-/*
- *	Cannot DMA over a 64K boundary on a PC
+/**
+ *	spans_boundary:
+ *	@skb: The buffer to check
+ *
+ *	Returns true if the buffer cross a DMA boundary on a PC. The poor
+ *	thing can only DMA within a 64K block not across the edges of it.
  */
  
 extern inline int spans_boundary(struct sk_buff *skb)
@@ -1373,7 +1649,11 @@
 	return 0;
 }
 
-/*
+/**
+ *	z8530_queue_xmit:
+ *	@c: The channel to use
+ *	@skb: The packet to kick down the channel
+ *
  *	Queue a packet for transmission. Because we have rather
  *	hard to hit interrupt latencies for the Z85230 per packet 
  *	even in DMA mode we do the flip to DMA buffer if needed here
@@ -1426,6 +1706,14 @@
 
 EXPORT_SYMBOL(z8530_queue_xmit);
 
+/**
+ *	z8530_get_stats:
+ *	@c: The channel to use
+ *
+ *	Get the statistics block. We keep the statistics in software as
+ *	the chip doesn't do it for us.
+ */
+ 
 struct net_device_stats *z8530_get_stats(struct z8530_channel *c)
 {
 	return &c->stats;
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wan/z85230.h linux/drivers/net/wan/z85230.h
--- v2.3.44/linux/drivers/net/wan/z85230.h	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/wan/z85230.h	Sat Feb 12 15:45:05 2000
@@ -304,8 +304,8 @@
 	 */
 	 
 	struct z8530_dev *dev;		/* Z85230 chip instance we are from */
-	int		ctrlio;		/* I/O ports */
-	int		dataio;
+	unsigned long	ctrlio;		/* I/O ports */
+	unsigned long	dataio;
 
 	/*
 	 *	For PC we encode this way.
@@ -395,7 +395,7 @@
 extern u8 z8530_hdlc_kilostream_85230[];
 extern u8 z8530_hdlc_kilostream[];
 extern void z8530_interrupt(int, void *, struct pt_regs *);
-extern void z8530_describe(struct z8530_dev *, char *mapping,int io);
+extern void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io);
 extern int z8530_init(struct z8530_dev *);
 extern int z8530_shutdown(struct z8530_dev *);
 extern int z8530_sync_open(struct net_device *, struct z8530_channel *);
diff -u --recursive --new-file v2.3.44/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.3.44/linux/drivers/net/wavelan.c	Tue Dec  7 09:32:44 1999
+++ linux/drivers/net/wavelan.c	Sat Feb 12 15:45:05 2000
@@ -6,9 +6,9 @@
  * Reorganisation and extension of the driver.
  * Original copyright follows (also see the end of this file).
  * See wavelan.p.h for details.
- */
-
-/*
+ *
+ *
+ *
  * AT&T GIS (nee NCR) WaveLAN card:
  *	An Ethernet-like radio transceiver
  *	controlled by an Intel 82586 coprocessor.
@@ -26,54 +26,49 @@
 /*
  * Wrapper for disabling interrupts.
  */
-static inline unsigned long
-wv_splhi(void)
-{
-  unsigned long flags;
-
-  save_flags(flags);
-  cli();
 
-  return(flags);
+static inline unsigned long wv_splhi(void)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	return (flags);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Wrapper for re-enabling interrupts.
  */
-static inline void
-wv_splx(unsigned long	flags)
+static inline void wv_splx(unsigned long flags)
 {
-  restore_flags(flags);
+	restore_flags(flags);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Translate irq number to PSA irq parameter
  */
-static u_char
-wv_irq_to_psa(int	irq)
+static u8 wv_irq_to_psa(int irq)
 {
-  if(irq < 0 || irq >= NELS(irqvals))
-    return 0;
+	if (irq < 0 || irq >= NELS(irqvals))
+		return 0;
 
-  return irqvals[irq];
+	return irqvals[irq];
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Translate PSA irq parameter to irq number 
  */
-static int __init 
-wv_psa_to_irq(u_char irqval)
+static int __init wv_psa_to_irq(u8 irqval)
 {
-  int	irq;
+	int irq;
 
-  for(irq = 0; irq < NELS(irqvals); irq++)
-    if(irqvals[irq] == irqval)
-      return irq;
+	for (irq = 0; irq < NELS(irqvals); irq++)
+		if (irqvals[irq] == irqval)
+			return irq;
 
-  return -1;
+	return -1;
 }
 
 #ifdef STRUCT_CHECK
@@ -82,21 +77,20 @@
  * Sanity routine to verify the sizes of the various WaveLAN interface
  * structures.
  */
-static char *
-wv_struct_check(void)
+static char *wv_struct_check(void)
 {
 #define	SC(t,s,n)	if (sizeof(t) != s) return(n);
 
-  SC(psa_t, PSA_SIZE, "psa_t");
-  SC(mmw_t, MMW_SIZE, "mmw_t");
-  SC(mmr_t, MMR_SIZE, "mmr_t");
-  SC(ha_t, HA_SIZE, "ha_t");
+	SC(psa_t, PSA_SIZE, "psa_t");
+	SC(mmw_t, MMW_SIZE, "mmw_t");
+	SC(mmr_t, MMR_SIZE, "mmr_t");
+	SC(ha_t, HA_SIZE, "ha_t");
 
 #undef	SC
 
-  return((char *) NULL);
-} /* wv_struct_check */
-#endif	/* STRUCT_CHECK */
+	return ((char *) NULL);
+}				/* wv_struct_check */
+#endif				/* STRUCT_CHECK */
 
 /********************* HOST ADAPTER SUBROUTINES *********************/
 /*
@@ -111,120 +105,106 @@
 /*
  * Read from card's Host Adaptor Status Register.
  */
-static inline u_short
-hasr_read(u_long	ioaddr)
+static inline u16 hasr_read(unsigned long ioaddr)
 {
-  return(inw(HASR(ioaddr)));
-} /* hasr_read */
+	return (inw(HASR(ioaddr)));
+}				/* hasr_read */
 
 /*------------------------------------------------------------------*/
 /*
  * Write to card's Host Adapter Command Register.
  */
-static inline void
-hacr_write(u_long	ioaddr,
-	   u_short	hacr)
+static inline void hacr_write(unsigned long ioaddr, u16 hacr)
 {
-  outw(hacr, HACR(ioaddr));
-} /* hacr_write */
+	outw(hacr, HACR(ioaddr));
+}				/* hacr_write */
 
 /*------------------------------------------------------------------*/
 /*
  * Write to card's Host Adapter Command Register. Include a delay for
  * those times when it is needed.
  */
-static inline void
-hacr_write_slow(u_long	ioaddr,
-		u_short	hacr)
+static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr)
 {
-  hacr_write(ioaddr, hacr);
-  /* delay might only be needed sometimes */
-  mdelay(1);
-} /* hacr_write_slow */
+	hacr_write(ioaddr, hacr);
+	/* delay might only be needed sometimes */
+	mdelay(1);
+}				/* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
 /*
  * Set the channel attention bit.
  */
-static inline void
-set_chan_attn(u_long	ioaddr,
-	      u_short	hacr)
+static inline void set_chan_attn(unsigned long ioaddr, u16 hacr)
 {
-  hacr_write(ioaddr, hacr | HACR_CA);
-} /* set_chan_attn */
+	hacr_write(ioaddr, hacr | HACR_CA);
+}				/* set_chan_attn */
 
 /*------------------------------------------------------------------*/
 /*
  * Reset, and then set host adaptor into default mode.
  */
-static inline void
-wv_hacr_reset(u_long	ioaddr)
+static inline void wv_hacr_reset(unsigned long ioaddr)
 {
-  hacr_write_slow(ioaddr, HACR_RESET);
-  hacr_write(ioaddr, HACR_DEFAULT);
-} /* wv_hacr_reset */
+	hacr_write_slow(ioaddr, HACR_RESET);
+	hacr_write(ioaddr, HACR_DEFAULT);
+}				/* wv_hacr_reset */
 
 /*------------------------------------------------------------------*/
 /*
  * Set the I/O transfer over the ISA bus to 8-bit mode
  */
-static inline void
-wv_16_off(u_long	ioaddr,
-	  u_short	hacr)
+static inline void wv_16_off(unsigned long ioaddr, u16 hacr)
 {
-  hacr &= ~HACR_16BITS;
-  hacr_write(ioaddr, hacr);
-} /* wv_16_off */
+	hacr &= ~HACR_16BITS;
+	hacr_write(ioaddr, hacr);
+}				/* wv_16_off */
 
 /*------------------------------------------------------------------*/
 /*
  * Set the I/O transfer over the ISA bus to 8-bit mode
  */
-static inline void
-wv_16_on(u_long		ioaddr,
-	 u_short	hacr)
+static inline void wv_16_on(unsigned long ioaddr, u16 hacr)
 {
-  hacr |= HACR_16BITS;
-  hacr_write(ioaddr, hacr);
-} /* wv_16_on */
+	hacr |= HACR_16BITS;
+	hacr_write(ioaddr, hacr);
+}				/* wv_16_on */
 
 /*------------------------------------------------------------------*/
 /*
  * Disable interrupts on the WaveLAN hardware.
  */
-static inline void
-wv_ints_off(device *	dev)
+static inline void wv_ints_off(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  u_long	x;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	
+	lp->hacr &= ~HACR_INTRON;
+	hacr_write(ioaddr, lp->hacr);
 
-  x = wv_splhi();
-
-  lp->hacr &= ~HACR_INTRON;
-  hacr_write(ioaddr, lp->hacr);
-
-  wv_splx(x);
-} /* wv_ints_off */
+	restore_flags(flags);
+}				/* wv_ints_off */
 
 /*------------------------------------------------------------------*/
 /*
  * Enable interrupts on the WaveLAN hardware.
  */
-static inline void
-wv_ints_on(device *	dev)
+static inline void wv_ints_on(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  u_long	x;
-
-  x = wv_splhi();
-
-  lp->hacr |= HACR_INTRON;
-  hacr_write(ioaddr, lp->hacr);
-
-  wv_splx(x);
-} /* wv_ints_on */
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	lp->hacr |= HACR_INTRON;
+	hacr_write(ioaddr, lp->hacr);
+	restore_flags(flags);
+}				/* wv_ints_on */
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
@@ -238,57 +218,48 @@
 /*
  * Read bytes from the PSA.
  */
-static void
-psa_read(u_long		ioaddr,
-	 u_short	hacr,
-	 int		o,	/* offset in PSA */
-	 u_char *	b,	/* buffer to fill */
-	 int		n)	/* size to read */
-{
-  wv_16_off(ioaddr, hacr);
-
-  while(n-- > 0)
-    {
-      outw(o, PIOR2(ioaddr));
-      o++;
-      *b++ = inb(PIOP2(ioaddr));
-    }
+static void psa_read(unsigned long ioaddr, u16 hacr, int o,	/* offset in PSA */
+		     u8 * b,	/* buffer to fill */
+		     int n)
+{				/* size to read */
+	wv_16_off(ioaddr, hacr);
+
+	while (n-- > 0) {
+		outw(o, PIOR2(ioaddr));
+		o++;
+		*b++ = inb(PIOP2(ioaddr));
+	}
 
-  wv_16_on(ioaddr, hacr);
-} /* psa_read */
+	wv_16_on(ioaddr, hacr);
+}				/* psa_read */
 
 /*------------------------------------------------------------------*/
 /*
  * Write the Parameter Storage Area to the WaveLAN card's memory.
  */
-static void
-psa_write(u_long	ioaddr,
-	  u_short	hacr,
-	  int		o,	/* Offset in PSA */
-	  u_char *	b,	/* Buffer in memory */
-	  int		n)	/* Length of buffer */
-{
-  int	count = 0;
-
-  wv_16_off(ioaddr, hacr);
-
-  while(n-- > 0)
-    {
-      outw(o, PIOR2(ioaddr));
-      o++;
-
-      outb(*b, PIOP2(ioaddr));
-      b++;
-
-      /* Wait for the memory to finish its write cycle */
-      count = 0;
-      while((count++ < 100) &&
-	    (hasr_read(ioaddr) & HASR_PSA_BUSY))
-	mdelay(1);
-    }
+static void psa_write(unsigned long ioaddr, u16 hacr, int o,	/* Offset in PSA */
+		      u8 * b,	/* Buffer in memory */
+		      int n)
+{				/* Length of buffer */
+	int count = 0;
+
+	wv_16_off(ioaddr, hacr);
+
+	while (n-- > 0) {
+		outw(o, PIOR2(ioaddr));
+		o++;
+
+		outb(*b, PIOP2(ioaddr));
+		b++;
+
+		/* Wait for the memory to finish its write cycle */
+		count = 0;
+		while ((count++ < 100) &&
+		       (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1);
+	}
 
-  wv_16_on(ioaddr, hacr);
-} /* psa_write */
+	wv_16_on(ioaddr, hacr);
+}				/* psa_write */
 
 #ifdef SET_PSA_CRC
 /*------------------------------------------------------------------*/
@@ -301,88 +272,80 @@
  * The Windows drivers don't use the CRC, but the AP and the PtP tool
  * depend on it.
  */
-static inline u_short
-psa_crc(u_char *	psa,	/* The PSA */
-	int		size)	/* Number of short for CRC */
-{
-  int		byte_cnt;	/* Loop on the PSA */
-  u_short	crc_bytes = 0;	/* Data in the PSA */
-  int		bit_cnt;	/* Loop on the bits of the short */
-
-  for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
-    {
-      crc_bytes ^= psa[byte_cnt];	/* Its an xor */
+static inline u16 psa_crc(u8 * psa,	/* The PSA */
+			      int size)
+{				/* Number of short for CRC */
+	int byte_cnt;		/* Loop on the PSA */
+	u16 crc_bytes = 0;	/* Data in the PSA */
+	int bit_cnt;		/* Loop on the bits of the short */
+
+	for (byte_cnt = 0; byte_cnt < size; byte_cnt++) {
+		crc_bytes ^= psa[byte_cnt];	/* Its an xor */
+
+		for (bit_cnt = 1; bit_cnt < 9; bit_cnt++) {
+			if (crc_bytes & 0x0001)
+				crc_bytes = (crc_bytes >> 1) ^ 0xA001;
+			else
+				crc_bytes >>= 1;
+		}
+	}
 
-      for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
-	{
-	  if(crc_bytes & 0x0001)
-	    crc_bytes = (crc_bytes >> 1) ^ 0xA001;
-	  else
-	    crc_bytes >>= 1 ;
-        }
-    }
-
-  return crc_bytes;
-} /* psa_crc */
-#endif	/* SET_PSA_CRC */
+	return crc_bytes;
+}				/* psa_crc */
+#endif				/* SET_PSA_CRC */
 
 /*------------------------------------------------------------------*/
 /*
  * update the checksum field in the Wavelan's PSA
  */
-static void
-update_psa_checksum(device *	dev,
-		    u_long	ioaddr,
-		    u_short	hacr)
+static void update_psa_checksum(device * dev, unsigned long ioaddr, u16 hacr)
 {
 #ifdef SET_PSA_CRC
-  psa_t		psa;
-  u_short	crc;
+	psa_t psa;
+	u16 crc;
 
-  /* read the parameter storage area */
-  psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
+	/* read the parameter storage area */
+	psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa));
 
-  /* update the checksum */
-  crc = psa_crc((unsigned char *) &psa,
-		sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
-		- sizeof(psa.psa_crc_status));
-
-  psa.psa_crc[0] = crc & 0xFF;
-  psa.psa_crc[1] = (crc & 0xFF00) >> 8;
-
-  /* Write it ! */
-  psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa,
-	    (unsigned char *)&psa.psa_crc, 2);
+	/* update the checksum */
+	crc = psa_crc((unsigned char *) &psa,
+		      sizeof(psa) - sizeof(psa.psa_crc[0]) -
+		      sizeof(psa.psa_crc[1])
+		      - sizeof(psa.psa_crc_status));
+
+	psa.psa_crc[0] = crc & 0xFF;
+	psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+
+	/* Write it ! */
+	psa_write(ioaddr, hacr, (char *) &psa.psa_crc - (char *) &psa,
+		  (unsigned char *) &psa.psa_crc, 2);
 
 #ifdef DEBUG_IOCTL_INFO
-  printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
-          dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+	printk(KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+	       dev->name, psa.psa_crc[0], psa.psa_crc[1]);
 
-  /* Check again (luxury !) */
-  crc = psa_crc ((unsigned char *) &psa,
-		 sizeof(psa) - sizeof(psa.psa_crc_status));
-
-  if(crc != 0)
-    printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
-#endif /* DEBUG_IOCTL_INFO */
-#endif	/* SET_PSA_CRC */
-} /* update_psa_checksum */
+	/* Check again (luxury !) */
+	crc = psa_crc((unsigned char *) &psa,
+		      sizeof(psa) - sizeof(psa.psa_crc_status));
+
+	if (crc != 0)
+		printk(KERN_WARNING
+		       "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n",
+		       dev->name);
+#endif				/* DEBUG_IOCTL_INFO */
+#endif				/* SET_PSA_CRC */
+}				/* update_psa_checksum */
 
 /*------------------------------------------------------------------*/
 /*
  * Write 1 byte to the MMC.
  */
-static inline void
-mmc_out(u_long		ioaddr,
-	u_short		o,
-	u_char		d)
-{
-  /* Wait for MMC to go idle */
-  while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
-    ;
+static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
+{
+	/* Wait for MMC to go idle */
+	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
 
-  outw((u_short) (((u_short) d << 8) | (o << 1) | 1),
-       MMCR(ioaddr));
+	outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr));
 }
 
 /*------------------------------------------------------------------*/
@@ -390,35 +353,27 @@
  * Routine to write bytes to the Modem Management Controller.
  * We start at the end because it is the way it should be!
  */
-static inline void
-mmc_write(u_long	ioaddr,
-	  u_char	o,
-	  u_char *	b,
-	  int		n)
-{
-  o += n;
-  b += n;
-
-  while(n-- > 0 )
-    mmc_out(ioaddr, --o, *(--b));
-} /* mmc_write */
+static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
+{
+	o += n;
+	b += n;
+
+	while (n-- > 0)
+		mmc_out(ioaddr, --o, *(--b));
+}				/* mmc_write */
 
 /*------------------------------------------------------------------*/
 /*
  * Read a byte from the MMC.
  * Optimised version for 1 byte, avoid using memory.
  */
-static inline u_char
-mmc_in(u_long	ioaddr,
-       u_short	o)
-{
-  while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
-    ;
-  outw(o << 1, MMCR(ioaddr));
-
-  while(inw(HASR(ioaddr)) & HASR_MMC_BUSY)
-    ;
-  return (u_char) (inw(MMCR(ioaddr)) >> 8);
+static inline u8 mmc_in(unsigned long ioaddr, u16 o)
+{
+	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	outw(o << 1, MMCR(ioaddr));
+
+	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	return (u8) (inw(MMCR(ioaddr)) >> 8);
 }
 
 /*------------------------------------------------------------------*/
@@ -429,33 +384,28 @@
  * (code has just been moved in the above function)
  * We start at the end because it is the way it should be!
  */
-static inline void
-mmc_read(u_long		ioaddr,
-	 u_char		o,
-	 u_char *	b,
-	 int		n)
-{
-  o += n;
-  b += n;
-
-  while(n-- > 0)
-    *(--b) = mmc_in(ioaddr, --o);
-} /* mmc_read */
+static inline void mmc_read(unsigned long ioaddr, u8 o, u8 * b, int n)
+{
+	o += n;
+	b += n;
+
+	while (n-- > 0)
+		*(--b) = mmc_in(ioaddr, --o);
+}				/* mmc_read */
 
 /*------------------------------------------------------------------*/
 /*
  * Get the type of encryption available.
  */
-static inline int
-mmc_encr(u_long		ioaddr)	/* I/O port of the card */
-{
-  int	temp;
-
-  temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail));
-  if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
-    return 0;
-  else
-    return temp;
+static inline int mmc_encr(unsigned long ioaddr)
+{				/* I/O port of the card */
+	int temp;
+
+	temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail));
+	if ((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
+		return 0;
+	else
+		return temp;
 }
 
 /*------------------------------------------------------------------*/
@@ -463,49 +413,47 @@
  * Wait for the frequency EEPROM to complete a command.
  * I hope this one will be optimally inlined.
  */
-static inline void
-fee_wait(u_long		ioaddr,	/* I/O port of the card */
-	 int		delay,	/* Base delay to wait for */
-	 int		number)	/* Number of time to wait */
-{
-  int		count = 0;	/* Wait only a limited time */
-
-  while((count++ < number) &&
-	(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))
-    udelay(delay);
+static inline void fee_wait(unsigned long ioaddr,	/* I/O port of the card */
+			    int delay,	/* Base delay to wait for */
+			    int number)
+{				/* Number of time to wait */
+	int count = 0;		/* Wait only a limited time */
+
+	while ((count++ < number) &&
+	       (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+		MMR_FEE_STATUS_BUSY)) udelay(delay);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Read bytes from the Frequency EEPROM (frequency select cards).
  */
-static void
-fee_read(u_long		ioaddr,	/* I/O port of the card */
-	 u_short	o,	/* destination offset */
-	 u_short *	b,	/* data buffer */
-	 int		n)	/* number of registers */
-{
-  b += n;		/* Position at the end of the area */
-
-  /* Write the address */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
-
-  /* Loop on all buffer */
-  while(n-- > 0)
-    {
-      /* Write the read command */
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
-
-      /* Wait until EEPROM is ready (should be quick). */
-      fee_wait(ioaddr, 10, 100);
-
-      /* Read the value. */
-      *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
-	      mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
-    }
+static void fee_read(unsigned long ioaddr,	/* I/O port of the card */
+		     u16 o,	/* destination offset */
+		     u16 * b,	/* data buffer */
+		     int n)
+{				/* number of registers */
+	b += n;			/* Position at the end of the area */
+
+	/* Write the address */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+	/* Loop on all buffer */
+	while (n-- > 0) {
+		/* Write the read command */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_READ);
+
+		/* Wait until EEPROM is ready (should be quick). */
+		fee_wait(ioaddr, 10, 100);
+
+		/* Read the value. */
+		*--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) |
+			mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
+	}
 }
 
-#ifdef WIRELESS_EXT	/* if the wireless extension exists in the kernel */
+#ifdef WIRELESS_EXT		/* if the wireless extension exists in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
@@ -514,83 +462,82 @@
  * be unprotected and the write enabled.
  * Jean II
  */
-static void
-fee_write(u_long	ioaddr,	/* I/O port of the card */
-	  u_short	o,	/* destination offset */
-	  u_short *	b,	/* data buffer */
-	  int		n)	/* number of registers */
-{
-  b += n;		/* Position at the end of the area. */
+static void fee_write(unsigned long ioaddr,	/* I/O port of the card */
+		      u16 o,	/* destination offset */
+		      u16 * b,	/* data buffer */
+		      int n)
+{				/* number of registers */
+	b += n;			/* Position at the end of the area. */
 
 #ifdef EEPROM_IS_PROTECTED	/* disabled */
 #ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-  /* Ask to read the protected register */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
+	/* Ask to read the protected register */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
 
-  fee_wait(ioaddr, 10, 100);
+	fee_wait(ioaddr, 10, 100);
 
-  /* Read the protected register. */
-  printk("Protected 2:  %02X-%02X\n",
-	 mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
-	 mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
-#endif	/* DOESNT_SEEM_TO_WORK */
-
-  /* Enable protected register. */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
-
-  fee_wait(ioaddr, 10, 100);
-
-  /* Unprotect area. */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+	/* Read the protected register. */
+	printk("Protected 2:  %02X-%02X\n",
+	       mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
+	       mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));
+#endif				/* DOESNT_SEEM_TO_WORK */
+
+	/* Enable protected register. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
+
+	fee_wait(ioaddr, 10, 100);
+
+	/* Unprotect area. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 #ifdef DOESNT_SEEM_TO_WORK	/* disabled */
-  /* or use: */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
-#endif	/* DOESNT_SEEM_TO_WORK */
-
-  fee_wait(ioaddr, 10, 100);
-#endif	/* EEPROM_IS_PROTECTED */
-
-  /* Write enable. */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
-
-  fee_wait(ioaddr, 10, 100);
-
-  /* Write the EEPROM address. */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
-
-  /* Loop on all buffer */
-  while(n-- > 0)
-    {
-      /* Write the value. */
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
-
-      /* Write the write command. */
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
-
-      /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
-      mdelay(10);
-      fee_wait(ioaddr, 10, 100);
-    }
-
-  /* Write disable. */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
+	/* or use: */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
+#endif				/* DOESNT_SEEM_TO_WORK */
+
+	fee_wait(ioaddr, 10, 100);
+#endif				/* EEPROM_IS_PROTECTED */
+
+	/* Write enable. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
+
+	fee_wait(ioaddr, 10, 100);
+
+	/* Write the EEPROM address. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+	/* Loop on all buffer */
+	while (n-- > 0) {
+		/* Write the value. */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
+
+		/* Write the write command. */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_WRITE);
+
+		/* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */
+		mdelay(10);
+		fee_wait(ioaddr, 10, 100);
+	}
+
+	/* Write disable. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
 
-  fee_wait(ioaddr, 10, 100);
+	fee_wait(ioaddr, 10, 100);
 
 #ifdef EEPROM_IS_PROTECTED	/* disabled */
-  /* Reprotect EEPROM. */
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
-  mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+	/* Reprotect EEPROM. */
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00);
+	mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
 
-  fee_wait(ioaddr, 10, 100);
-#endif	/* EEPROM_IS_PROTECTED */
+	fee_wait(ioaddr, 10, 100);
+#endif				/* EEPROM_IS_PROTECTED */
 }
-#endif	/* WIRELESS_EXT */
+#endif				/* WIRELESS_EXT */
 
 /************************ I82586 SUBROUTINES *************************/
 /*
@@ -602,68 +549,61 @@
  * Read bytes from the on-board RAM.
  * Why does inlining this function make it fail?
  */
-static /*inline*/ void
-obram_read(u_long	ioaddr,
-	   u_short	o,
-	   u_char *	b,
-	   int		n)
+static /*inline */ void obram_read(unsigned long ioaddr,
+				   u16 o, u8 * b, int n)
 {
-  outw(o, PIOR1(ioaddr));
-  insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
+	outw(o, PIOR1(ioaddr));
+	insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Write bytes to the on-board RAM.
  */
-static inline void
-obram_write(u_long	ioaddr,
-	    u_short	o,
-	    u_char *	b,
-	    int		n)
+static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n)
 {
-  outw(o, PIOR1(ioaddr));
-  outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
+	outw(o, PIOR1(ioaddr));
+	outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Acknowledge the reading of the status issued by the i82586.
  */
-static void
-wv_ack(device *		dev)
+static void wv_ack(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  u_short	scb_cs;
-  int		i;
-
-  obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
-	     (unsigned char *) &scb_cs, sizeof(scb_cs));
-  scb_cs &= SCB_ST_INT;
-
-  if(scb_cs == 0)
-    return;
-
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-	      (unsigned char *) &scb_cs, sizeof(scb_cs));
-
-  set_chan_attn(ioaddr, lp->hacr);
-
-  for(i = 1000; i > 0; i--)
-    {
-      obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
-      if(scb_cs == 0)
-	break;
-
-      udelay(10);
-    }
-  udelay(100);
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cs;
+	int i;
+
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+		   (unsigned char *) &scb_cs, sizeof(scb_cs));
+	scb_cs &= SCB_ST_INT;
+
+	if (scb_cs == 0)
+		return;
+
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+			   (unsigned char *) &scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
+
+		udelay(10);
+	}
+	udelay(100);
 
 #ifdef DEBUG_CONFIG_ERROR
-  if(i <= 0)
-    printk(KERN_INFO "%s: wv_ack(): board not accepting command.\n",
-	   dev->name);
+	if (i <= 0)
+		printk(KERN_INFO
+		       "%s: wv_ack(): board not accepting command.\n",
+		       dev->name);
 #endif
 }
 
@@ -672,48 +612,45 @@
  * Set channel attention bit and busy wait until command has
  * completed, then acknowledge completion of the command.
  */
-static inline int
-wv_synchronous_cmd(device *	dev,
-		   const char *	str)
+static inline int wv_synchronous_cmd(device * dev, const char *str)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  u_short	scb_cmd;
-  ach_t		cb;
-  int		i;
-
-  scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-	      (unsigned char *) &scb_cmd, sizeof(scb_cmd));
-
-  set_chan_attn(ioaddr, lp->hacr);
-
-  for (i = 1000; i > 0; i--)
-    {
-      obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
-      if (cb.ac_status & AC_SFLD_C)
-	break;
-
-      udelay(10);
-    }
-  udelay(100);
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cmd;
+	ach_t cb;
+	int i;
+
+	scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cmd, sizeof(scb_cmd));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb,
+			   sizeof(cb));
+		if (cb.ac_status & AC_SFLD_C)
+			break;
 
-  if(i <= 0 || !(cb.ac_status & AC_SFLD_OK))
-    {
+		udelay(10);
+	}
+	udelay(100);
+
+	if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: %s failed; status = 0x%x\n",
-	     dev->name, str, cb.ac_status);
+		printk(KERN_INFO "%s: %s failed; status = 0x%x\n",
+		       dev->name, str, cb.ac_status);
 #endif
 #ifdef DEBUG_I82586_SHOW
-      wv_scb_show(ioaddr);
+		wv_scb_show(ioaddr);
 #endif
-      return -1;
-    }
+		return -1;
+	}
 
-  /* Ack the status */
-  wv_ack(dev);
+	/* Ack the status */
+	wv_ack(dev);
 
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -722,60 +659,64 @@
  * Check if done, and if OK.
  */
 static inline int
-wv_config_complete(device *	dev,
-		   u_long	ioaddr,
-		   net_local *	lp)
-{
-  unsigned short	mcs_addr;
-  unsigned short	status;
-  int			ret;
+wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
+{
+	unsigned short mcs_addr;
+	unsigned short status;
+	int ret;
 
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);
 #endif
 
-  mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
-    + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
+	mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t)
+	    + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t);
 
-  /* Read the status of the last command (set mc list). */
-  obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status));
+	/* Read the status of the last command (set mc list). */
+	obram_read(ioaddr, acoff(mcs_addr, ac_status),
+		   (unsigned char *) &status, sizeof(status));
 
-  /* If not completed -> exit */
-  if((status & AC_SFLD_C) == 0)
-    ret = 0;		/* Not ready to be scrapped */
-  else
-    {
+	/* If not completed -> exit */
+	if ((status & AC_SFLD_C) == 0)
+		ret = 0;	/* Not ready to be scrapped */
+	else {
 #ifdef DEBUG_CONFIG_ERROR
-      unsigned short	cfg_addr;
-      unsigned short	ias_addr;
-
-      /* Check mc_config command */
-      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);
+		unsigned short cfg_addr;
+		unsigned short ias_addr;
 
-      /* check ia-config command */
-      ias_addr = mcs_addr - sizeof(ac_ias_t);
-      obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(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);
-
-      /* Check config command. */
-      cfg_addr = ias_addr - sizeof(ac_cfg_t);
-      obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(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);
-#endif	/* DEBUG_CONFIG_ERROR */
+		/* Check mc_config command */
+		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);
+
+		/* check ia-config command */
+		ias_addr = mcs_addr - sizeof(ac_ias_t);
+		obram_read(ioaddr, acoff(ias_addr, ac_status),
+			   (unsigned char *) &status, sizeof(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);
+
+		/* Check config command. */
+		cfg_addr = ias_addr - sizeof(ac_cfg_t);
+		obram_read(ioaddr, acoff(cfg_addr, ac_status),
+			   (unsigned char *) &status, sizeof(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);
+#endif				/* DEBUG_CONFIG_ERROR */
 
-      ret = 1;		/* Ready to be scrapped */
-    }
+		ret = 1;	/* Ready to be scrapped */
+	}
 
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, ret);
+	printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name,
+	       ret);
 #endif
-  return ret;
+	return ret;
 }
 
 /*------------------------------------------------------------------*/
@@ -783,141 +724,137 @@
  * Command completion interrupt.
  * Reclaim as many freed tx buffers as we can.
  */
-static int
-wv_complete(device *	dev,
-	    u_long	ioaddr,
-	    net_local *	lp)
+static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp)
 {
-  int	nreaped = 0;
+	int nreaped = 0;
 
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);
 #endif
 
-  /* Loop on all the transmit buffers */
-  while(lp->tx_first_in_use != I82586NULL)
-    {
-      unsigned short	tx_status;
-
-      /* Read the first transmit buffer */
-      obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
-
-      /* If not completed -> exit */
-      if((tx_status & AC_SFLD_C) == 0)
-	break;
-
-      /* Hack for reconfiguration */
-      if(tx_status == 0xFFFF)
-	if(!wv_config_complete(dev, ioaddr, lp))
-	  break;	/* Not completed */
-
-      /* We now remove this buffer */
-      nreaped++;
-      --lp->tx_n_in_use;
+	/* Loop on all the transmit buffers */
+	while (lp->tx_first_in_use != I82586NULL) {
+		unsigned short tx_status;
+
+		/* Read the first transmit buffer */
+		obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status),
+			   (unsigned char *) &tx_status,
+			   sizeof(tx_status));
+
+		/* If not completed -> exit */
+		if ((tx_status & AC_SFLD_C) == 0)
+			break;
+
+		/* Hack for reconfiguration */
+		if (tx_status == 0xFFFF)
+			if (!wv_config_complete(dev, ioaddr, lp))
+				break;	/* Not completed */
+
+		/* We now remove this buffer */
+		nreaped++;
+		--lp->tx_n_in_use;
 
 /*
 if (lp->tx_n_in_use > 0)
 	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
 */
 
-      /* Was it the last one? */
-      if(lp->tx_n_in_use <= 0)
-	lp->tx_first_in_use = I82586NULL;
-      else
-	{
-	  /* Next one in the chain */
-	  lp->tx_first_in_use += TXBLOCKZ;
-	  if(lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-	    lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ;
-	}
-
-      /* Hack for reconfiguration */
-      if(tx_status == 0xFFFF)
-	continue;
-
-      /* Now, check status of the finished command */
-      if(tx_status & AC_SFLD_OK)
-	{
-	  int	ncollisions;
-
-	  lp->stats.tx_packets++;
-	  ncollisions = tx_status & AC_SFLD_MAXCOL;
-	  lp->stats.collisions += ncollisions;
+		/* Was it the last one? */
+		if (lp->tx_n_in_use <= 0)
+			lp->tx_first_in_use = I82586NULL;
+		else {
+			/* Next one in the chain */
+			lp->tx_first_in_use += TXBLOCKZ;
+			if (lp->tx_first_in_use >=
+			    OFFSET_CU +
+			    NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -=
+				    NTXBLOCKS * TXBLOCKZ;
+		}
+
+		/* Hack for reconfiguration */
+		if (tx_status == 0xFFFF)
+			continue;
+
+		/* Now, check status of the finished command */
+		if (tx_status & AC_SFLD_OK) {
+			int ncollisions;
+
+			lp->stats.tx_packets++;
+			ncollisions = tx_status & AC_SFLD_MAXCOL;
+			lp->stats.collisions += ncollisions;
 #ifdef DEBUG_TX_INFO
-	  if(ncollisions > 0)
-	    printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n",
-		   dev->name, ncollisions);
-#endif
-	}
-      else
-	{
-	  lp->stats.tx_errors++;
-	  if(tx_status & AC_SFLD_S10)
-	    {
-	      lp->stats.tx_carrier_errors++;
+			if (ncollisions > 0)
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx completed after %d collisions.\n",
+				       dev->name, ncollisions);
+#endif
+		} else {
+			lp->stats.tx_errors++;
+			if (tx_status & AC_SFLD_S10) {
+				lp->stats.tx_carrier_errors++;
 #ifdef DEBUG_TX_FAIL
-	      printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n",
-		     dev->name);
-#endif
-	    }
-	  if(tx_status & AC_SFLD_S9)
-	    {
-	      lp->stats.tx_carrier_errors++;
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: no CS.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S9) {
+				lp->stats.tx_carrier_errors++;
 #ifdef DEBUG_TX_FAIL
-	      printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n",
-		     dev->name);
-#endif
-	    }
-	  if(tx_status & AC_SFLD_S8)
-	    {
-	      lp->stats.tx_fifo_errors++;
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: lost CTS.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S8) {
+				lp->stats.tx_fifo_errors++;
 #ifdef DEBUG_TX_FAIL
-	      printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n",
-		     dev->name);
-#endif
-	    }
-	  if(tx_status & AC_SFLD_S6)
-	    {
-	      lp->stats.tx_heartbeat_errors++;
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: slow DMA.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S6) {
+				lp->stats.tx_heartbeat_errors++;
 #ifdef DEBUG_TX_FAIL
-	      printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n",
-		     dev->name);
-#endif
-	    }
-	  if(tx_status & AC_SFLD_S5)
-	    {
-	      lp->stats.tx_aborted_errors++;
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: heart beat.\n",
+				       dev->name);
+#endif
+			}
+			if (tx_status & AC_SFLD_S5) {
+				lp->stats.tx_aborted_errors++;
 #ifdef DEBUG_TX_FAIL
-	      printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n",
-		     dev->name);
+				printk(KERN_DEBUG
+				       "%s: wv_complete(): tx error: too many collisions.\n",
+				       dev->name);
 #endif
-	    }
-	}
+			}
+		}
 
 #ifdef DEBUG_TX_INFO
-      printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
-	     dev->name, tx_status);
+		printk(KERN_DEBUG
+		       "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
+		       dev->name, tx_status);
 #endif
-    }
+	}
 
 #ifdef DEBUG_INTERRUPT_INFO
-  if(nreaped > 1)
-    printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", dev->name, nreaped);
+	if (nreaped > 1)
+		printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n",
+		       dev->name, nreaped);
 #endif
 
-  /*
-   * Inform upper layers.
-   */
-  if(lp->tx_n_in_use < NTXBLOCKS - 1)
-    {
-      dev->tbusy = 0;
-      mark_bh(NET_BH);
-    }
-
+	/*
+	 * Inform upper layers.
+	 */
+	if (lp->tx_n_in_use < NTXBLOCKS - 1) {
+		netif_wake_queue(dev);
+	}
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);
 #endif
-  return nreaped;
+	return nreaped;
 }
 
 /*------------------------------------------------------------------*/
@@ -929,22 +866,21 @@
  * wavelan_interrupt is not an option), so you may experience
  * delays sometimes.
  */
-static inline void
-wv_82586_reconfig(device *	dev)
+static inline void wv_82586_reconfig(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
+	net_local *lp = (net_local *) dev->priv;
 
-  /* Check if we can do it now ! */
-  if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0))
-    {
-      lp->reconfig_82586 = 1;
+	/* Check if we can do it now ! */
+	if (!test_bit(LINK_STATE_START, &dev->state) &&
+	    test_bit(LINK_STATE_XOFF, &dev->state)) {
+		lp->reconfig_82586 = 1;
 #ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (busy = %ld, start = %d)\n",
-	     dev->name, dev->tbusy, dev->start);
+		printk(KERN_DEBUG
+		       "%s: wv_82586_reconfig(): delayed (state = %lX)\n",
+			       dev->name, dev->state);
 #endif
-    }
-  else
-    wv_82586_config(dev);
+	} else
+		wv_82586_config(dev);
 }
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
@@ -958,89 +894,73 @@
 /*
  * Print the formatted contents of the Parameter Storage Area.
  */
-static void
-wv_psa_show(psa_t *	p)
+static void wv_psa_show(psa_t * p)
 {
-  printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
-  printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
-	 p->psa_io_base_addr_1,
-	 p->psa_io_base_addr_2,
-	 p->psa_io_base_addr_3,
-	 p->psa_io_base_addr_4);
-  printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
-	 p->psa_rem_boot_addr_1,
-	 p->psa_rem_boot_addr_2,
-	 p->psa_rem_boot_addr_3);
-  printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
-  printk("psa_int_req_no: %d\n", p->psa_int_req_no);
+	printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
+	printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
+	       p->psa_io_base_addr_1,
+	       p->psa_io_base_addr_2,
+	       p->psa_io_base_addr_3, p->psa_io_base_addr_4);
+	printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
+	       p->psa_rem_boot_addr_1,
+	       p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3);
+	printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
+	printk("psa_int_req_no: %d\n", p->psa_int_req_no);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 p->psa_unused0[0],
-	 p->psa_unused0[1],
-	 p->psa_unused0[2],
-	 p->psa_unused0[3],
-	 p->psa_unused0[4],
-	 p->psa_unused0[5],
-	 p->psa_unused0[6]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_univ_mac_addr[0],
-	 p->psa_univ_mac_addr[1],
-	 p->psa_univ_mac_addr[2],
-	 p->psa_univ_mac_addr[3],
-	 p->psa_univ_mac_addr[4],
-	 p->psa_univ_mac_addr[5]);
-  printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_local_mac_addr[0],
-	 p->psa_local_mac_addr[1],
-	 p->psa_local_mac_addr[2],
-	 p->psa_local_mac_addr[3],
-	 p->psa_local_mac_addr[4],
-	 p->psa_local_mac_addr[5]);
-  printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
-  printk("psa_comp_number: %d, ", p->psa_comp_number);
-  printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
-  printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
-	 p->psa_feature_select);
-  printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
-  printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
-  printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
-  printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]);
-  printk("psa_nwid_select: %d\n", p->psa_nwid_select);
-  printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select);
-  printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_encryption_key[0],
-	 p->psa_encryption_key[1],
-	 p->psa_encryption_key[2],
-	 p->psa_encryption_key[3],
-	 p->psa_encryption_key[4],
-	 p->psa_encryption_key[5],
-	 p->psa_encryption_key[6],
-	 p->psa_encryption_key[7]);
-  printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
-  printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
-	 p->psa_call_code[0]);
-  printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 p->psa_call_code[0],
-	 p->psa_call_code[1],
-	 p->psa_call_code[2],
-	 p->psa_call_code[3],
-	 p->psa_call_code[4],
-	 p->psa_call_code[5],
-	 p->psa_call_code[6],
-	 p->psa_call_code[7]);
+	printk(KERN_DEBUG
+	       "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	       p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
+	       p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
+	       p->psa_unused0[6]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG
+	       "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
+	       p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
+	       p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
+	printk(KERN_DEBUG
+	       "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
+	       p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
+	       p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
+	printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
+	       p->psa_univ_local_sel);
+	printk("psa_comp_number: %d, ", p->psa_comp_number);
+	printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
+	printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
+	       p->psa_feature_select);
+	printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
+	printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
+	printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
+	printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0],
+	       p->psa_nwid[1]);
+	printk("psa_nwid_select: %d\n", p->psa_nwid_select);
+	printk(KERN_DEBUG "psa_encryption_select: %d, ",
+	       p->psa_encryption_select);
+	printk
+	    ("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	     p->psa_encryption_key[0], p->psa_encryption_key[1],
+	     p->psa_encryption_key[2], p->psa_encryption_key[3],
+	     p->psa_encryption_key[4], p->psa_encryption_key[5],
+	     p->psa_encryption_key[6], p->psa_encryption_key[7]);
+	printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
+	printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
+	       p->psa_call_code[0]);
+	printk
+	    ("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	     p->psa_call_code[0], p->psa_call_code[1], p->psa_call_code[2],
+	     p->psa_call_code[3], p->psa_call_code[4], p->psa_call_code[5],
+	     p->psa_call_code[6], p->psa_call_code[7]);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
-	 p->psa_reserved[0],
-	 p->psa_reserved[1],
-	 p->psa_reserved[2],
-	 p->psa_reserved[3]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
-  printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
-  printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
-} /* wv_psa_show */
-#endif	/* DEBUG_PSA_SHOW */
+	printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+	       p->psa_reserved[0],
+	       p->psa_reserved[1], p->psa_reserved[2], p->psa_reserved[3]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
+	printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
+	printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
+}				/* wv_psa_show */
+#endif				/* DEBUG_PSA_SHOW */
 
 #ifdef DEBUG_MMC_SHOW
 /*------------------------------------------------------------------*/
@@ -1048,411 +968,432 @@
  * Print the formatted status of the Modem Management Controller.
  * This function needs to be completed.
  */
-static void
-wv_mmc_show(device *	dev)
+static void wv_mmc_show(device * dev)
 {
-  u_long	ioaddr = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
-  mmr_t		m;
-
-  /* Basic check */
-  if(hasr_read(ioaddr) & HASR_NO_CLK)
-    {
-      printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n",
-	     dev->name);
-      return;
-    }
-
-  /* Read the mmc */
-  mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-  mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m));
-  mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
-#ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
-  /* Don't forget to update statistics */
-  lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-#endif	/* WIRELESS_EXT */
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	mmr_t m;
+
+	/* Basic check */
+	if (hasr_read(ioaddr) & HASR_NO_CLK) {
+		printk(KERN_WARNING
+		       "%s: wv_mmc_show: modem not connected\n",
+		       dev->name);
+		return;
+	}
+
+	/* Read the mmc */
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+	mmc_read(ioaddr, 0, (u8 *) & m, sizeof(m));
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+#ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
+	/* Don't forget to update statistics */
+	lp->wstats.discard.nwid +=
+	    (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+#endif				/* WIRELESS_EXT */
 
-  printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
+	printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 m.mmr_unused0[0],
-	 m.mmr_unused0[1],
-	 m.mmr_unused0[2],
-	 m.mmr_unused0[3],
-	 m.mmr_unused0[4],
-	 m.mmr_unused0[5],
-	 m.mmr_unused0[6],
-	 m.mmr_unused0[7]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
-	 m.mmr_des_avail, m.mmr_des_status);
+	printk(KERN_DEBUG
+	       "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	       m.mmr_unused0[0], m.mmr_unused0[1], m.mmr_unused0[2],
+	       m.mmr_unused0[3], m.mmr_unused0[4], m.mmr_unused0[5],
+	       m.mmr_unused0[6], m.mmr_unused0[7]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
+	       m.mmr_des_avail, m.mmr_des_status);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
-	 m.mmr_unused1[0],
-	 m.mmr_unused1[1],
-	 m.mmr_unused1[2],
-	 m.mmr_unused1[3],
-	 m.mmr_unused1[4]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
-	 m.mmr_dce_status,
-	 (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"",
-	 (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
-	 "loop test indicated," : "",
-	 (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "",
-	 (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
-	 "jabber timer expired," : "");
-  printk(KERN_DEBUG "Dsp ID: %02X\n",
-	 m.mmr_dsp_id);
+	printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
+	       m.mmr_unused1[0],
+	       m.mmr_unused1[1],
+	       m.mmr_unused1[2], m.mmr_unused1[3], m.mmr_unused1[4]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
+	       m.mmr_dce_status,
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ?
+	       "energy detected," : "",
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
+	       "loop test indicated," : "",
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ?
+	       "transmitter on," : "",
+	       (m.
+		mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
+	       "jabber timer expired," : "");
+	printk(KERN_DEBUG "Dsp ID: %02X\n", m.mmr_dsp_id);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
-	 m.mmr_unused2[0],
-	 m.mmr_unused2[1]);
-#endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
-	 (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
-	 (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
-  printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
-	 m.mmr_thr_pre_set & MMR_THR_PRE_SET,
-	 (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below");
-  printk(KERN_DEBUG "signal_lvl: %d [%s], ",
-	 m.mmr_signal_lvl & MMR_SIGNAL_LVL,
-	 (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg");
-  printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL,
-	 (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update");
-  printk("sgnl_qual: 0x%x [%s]\n",
-	 m.mmr_sgnl_qual & MMR_SGNL_QUAL,
-	 (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0");
+	printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
+	       m.mmr_unused2[0], m.mmr_unused2[1]);
+#endif				/* DEBUG_SHOW_UNUSED */
+	printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
+	       (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
+	       (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+	printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
+	       m.mmr_thr_pre_set & MMR_THR_PRE_SET,
+	       (m.
+		mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" :
+	       "below");
+	printk(KERN_DEBUG "signal_lvl: %d [%s], ",
+	       m.mmr_signal_lvl & MMR_SIGNAL_LVL,
+	       (m.
+		mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" :
+	       "no new msg");
+	printk("silence_lvl: %d [%s], ",
+	       m.mmr_silence_lvl & MMR_SILENCE_LVL,
+	       (m.
+		mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" :
+	       "no new update");
+	printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
+	       (m.
+		mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" :
+	       "Antenna 0");
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
-#endif	/* DEBUG_SHOW_UNUSED */
-} /* wv_mmc_show */
-#endif	/* DEBUG_MMC_SHOW */
+	printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
+#endif				/* DEBUG_SHOW_UNUSED */
+}				/* wv_mmc_show */
+#endif				/* DEBUG_MMC_SHOW */
 
 #ifdef DEBUG_I82586_SHOW
 /*------------------------------------------------------------------*/
 /*
  * Print the last block of the i82586 memory.
  */
-static void
-wv_scb_show(u_long	ioaddr)
+static void wv_scb_show(unsigned long ioaddr)
 {
-  scb_t		scb;
+	scb_t scb;
 
-  obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));   
+	obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+		   sizeof(scb));
 
-  printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
+	printk(KERN_DEBUG "##### WaveLAN system control block: #####\n");
 
-  printk(KERN_DEBUG "status: ");
-  printk("stat 0x%x[%s%s%s%s] ",
-	 (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12,
-	 (scb.scb_status & SCB_ST_CX) ? "command completion interrupt," : "",
-	 (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
-	 (scb.scb_status & SCB_ST_CNA) ? "command unit not active," : "",
-	 (scb.scb_status & SCB_ST_RNR) ? "receiving unit not ready," : "");
-  printk("cus 0x%x[%s%s%s] ",
-	 (scb.scb_status & SCB_ST_CUS) >> 8,
-	 ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "",
-	 ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_SUSP) ? "suspended" : "",
-	 ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_ACTV) ? "active" : "");
-  printk("rus 0x%x[%s%s%s%s]\n",
-	 (scb.scb_status & SCB_ST_RUS) >> 4,
-	 ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_IDLE) ? "idle" : "",
-	 ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_SUSP) ? "suspended" : "",
-	 ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_NRES) ? "no resources" : "",
-	 ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_RDY) ? "ready" : "");
-
-  printk(KERN_DEBUG "command: ");
-  printk("ack 0x%x[%s%s%s%s] ",
-	 (scb.scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
-	 (scb.scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
-	 (scb.scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
-	 (scb.scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
-	 (scb.scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : "");
-  printk("cuc 0x%x[%s%s%s%s%s] ",
-	 (scb.scb_command & SCB_CMD_CUC) >> 8,
-	 ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_NOP) ? "nop" : "",
-	 ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
-	 ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_RES) ? "resume execution" : "",
-	 ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_SUS) ? "suspend execution" : "",
-	 ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_ABT) ? "abort execution" : "");
-  printk("ruc 0x%x[%s%s%s%s%s]\n",
-	 (scb.scb_command & SCB_CMD_RUC) >> 4,
-	 ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_NOP) ? "nop" : "",
-	 ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
-	 ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_RES) ? "resume reception" : "",
-	 ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_SUS) ? "suspend reception" : "",
-	 ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_ABT) ? "abort reception" : "");
-
-  printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset);
-  printk("rfa_offset 0x%x\n", scb.scb_rfa_offset);
-
-  printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs);
-  printk("alnerrs %d ", scb.scb_alnerrs);
-  printk("rscerrs %d ", scb.scb_rscerrs);
-  printk("ovrnerrs %d\n", scb.scb_ovrnerrs);
+	printk(KERN_DEBUG "status: ");
+	printk("stat 0x%x[%s%s%s%s] ",
+	       (scb.
+		scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA |
+			      SCB_ST_RNR)) >> 12,
+	       (scb.
+		scb_status & SCB_ST_CX) ? "command completion interrupt," :
+	       "", (scb.scb_status & SCB_ST_FR) ? "frame received," : "",
+	       (scb.
+		scb_status & SCB_ST_CNA) ? "command unit not active," : "",
+	       (scb.
+		scb_status & SCB_ST_RNR) ? "receiving unit not ready," :
+	       "");
+	printk("cus 0x%x[%s%s%s] ", (scb.scb_status & SCB_ST_CUS) >> 8,
+	       ((scb.scb_status & SCB_ST_CUS) ==
+		SCB_ST_CUS_IDLE) ? "idle" : "",
+	       ((scb.scb_status & SCB_ST_CUS) ==
+		SCB_ST_CUS_SUSP) ? "suspended" : "",
+	       ((scb.scb_status & SCB_ST_CUS) ==
+		SCB_ST_CUS_ACTV) ? "active" : "");
+	printk("rus 0x%x[%s%s%s%s]\n", (scb.scb_status & SCB_ST_RUS) >> 4,
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_IDLE) ? "idle" : "",
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_SUSP) ? "suspended" : "",
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_NRES) ? "no resources" : "",
+	       ((scb.scb_status & SCB_ST_RUS) ==
+		SCB_ST_RUS_RDY) ? "ready" : "");
+
+	printk(KERN_DEBUG "command: ");
+	printk("ack 0x%x[%s%s%s%s] ",
+	       (scb.
+		scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR |
+			       SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12,
+	       (scb.
+		scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "",
+	       (scb.
+		scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "",
+	       (scb.
+		scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "",
+	       (scb.
+		scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : "");
+	printk("cuc 0x%x[%s%s%s%s%s] ",
+	       (scb.scb_command & SCB_CMD_CUC) >> 8,
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_NOP) ? "nop" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_GO) ? "start cbl_offset" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_RES) ? "resume execution" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_SUS) ? "suspend execution" : "",
+	       ((scb.scb_command & SCB_CMD_CUC) ==
+		SCB_CMD_CUC_ABT) ? "abort execution" : "");
+	printk("ruc 0x%x[%s%s%s%s%s]\n",
+	       (scb.scb_command & SCB_CMD_RUC) >> 4,
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_NOP) ? "nop" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_GO) ? "start rfa_offset" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_RES) ? "resume reception" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_SUS) ? "suspend reception" : "",
+	       ((scb.scb_command & SCB_CMD_RUC) ==
+		SCB_CMD_RUC_ABT) ? "abort reception" : "");
+
+	printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset);
+	printk("rfa_offset 0x%x\n", scb.scb_rfa_offset);
+
+	printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs);
+	printk("alnerrs %d ", scb.scb_alnerrs);
+	printk("rscerrs %d ", scb.scb_rscerrs);
+	printk("ovrnerrs %d\n", scb.scb_ovrnerrs);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Print the formatted status of the i82586's receive unit.
  */
-static void
-wv_ru_show(device *	dev)
+static void wv_ru_show(device * dev)
 {
-  /* net_local *lp = (net_local *) dev->priv; */
+	/* net_local *lp = (net_local *) dev->priv; */
 
-  printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n");
-  printk(KERN_DEBUG "ru:");
-  /*
-   * Not implemented yet
-   */
-  printk("\n");
-} /* wv_ru_show */
+	printk(KERN_DEBUG
+	       "##### WaveLAN i82586 receiver unit status: #####\n");
+	printk(KERN_DEBUG "ru:");
+	/*
+	 * Not implemented yet
+	 */
+	printk("\n");
+}				/* wv_ru_show */
 
 /*------------------------------------------------------------------*/
 /*
  * Display info about one control block of the i82586 memory.
  */
-static void
-wv_cu_show_one(device *		dev,
-	       net_local *	lp,
-	       int		i,
-	       u_short		p)
+static void wv_cu_show_one(device * dev, net_local * lp, int i, u16 p)
 {
-  u_long		ioaddr;
-  ac_tx_t		actx;
+	unsigned long ioaddr;
+	ac_tx_t actx;
 
-  ioaddr = dev->base_addr;
+	ioaddr = dev->base_addr;
 
-  printk("%d: 0x%x:", i, p);
+	printk("%d: 0x%x:", i, p);
 
-  obram_read(ioaddr, p, (unsigned char *)&actx, sizeof(actx));
-  printk(" status=0x%x,", actx.tx_h.ac_status);
-  printk(" command=0x%x,", actx.tx_h.ac_command);
+	obram_read(ioaddr, p, (unsigned char *) &actx, sizeof(actx));
+	printk(" status=0x%x,", actx.tx_h.ac_status);
+	printk(" command=0x%x,", actx.tx_h.ac_command);
 
-  /*
-  {
-    tbd_t	tbd;
+	/*
+	   {
+	   tbd_t      tbd;
 
-    obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
-    printk(" tbd_status=0x%x,", tbd.tbd_status);
-  }
-  */
+	   obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd));
+	   printk(" tbd_status=0x%x,", tbd.tbd_status);
+	   }
+	 */
 
-  printk("|");
+	printk("|");
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Print status of the command unit of the i82586.
  */
-static void
-wv_cu_show(device *	dev)
+static void wv_cu_show(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  unsigned int	i;
-  u_short	p;
-
-  printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n");
-
-  printk(KERN_DEBUG);
-  for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++)
-    {
-      wv_cu_show_one(dev, lp, i, p);
-
-      p += TXBLOCKZ;
-      if(p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-	p -= NTXBLOCKS * TXBLOCKZ;
-    }
-  printk("\n");
+	net_local *lp = (net_local *) dev->priv;
+	unsigned int i;
+	u16 p;
+
+	printk(KERN_DEBUG
+	       "##### WaveLAN i82586 command unit status: #####\n");
+
+	printk(KERN_DEBUG);
+	for (i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) {
+		wv_cu_show_one(dev, lp, i, p);
+
+		p += TXBLOCKZ;
+		if (p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+			p -= NTXBLOCKS * TXBLOCKZ;
+	}
+	printk("\n");
 }
-#endif	/* DEBUG_I82586_SHOW */
+#endif				/* DEBUG_I82586_SHOW */
 
 #ifdef DEBUG_DEVICE_SHOW
 /*------------------------------------------------------------------*/
 /*
  * Print the formatted status of the WaveLAN PCMCIA device driver.
  */
-static void
-wv_dev_show(device *	dev)
+static void wv_dev_show(device * dev)
 {
-  printk(KERN_DEBUG "dev:");
-  printk(" start=%d,", dev->start);
-  printk(" tbusy=%ld,", dev->tbusy);
-  printk(" interrupt=%d,", dev->interrupt);
-  printk(" trans_start=%ld,", dev->trans_start);
-  printk(" flags=0x%x,", dev->flags);
-  printk("\n");
-} /* wv_dev_show */
+	printk(KERN_DEBUG "dev:");
+	printk(" state=%lX,", dev->state);
+	printk(" trans_start=%ld,", dev->trans_start);
+	printk(" flags=0x%x,", dev->flags);
+	printk("\n");
+}				/* wv_dev_show */
 
 /*------------------------------------------------------------------*/
 /*
  * Print the formatted status of the WaveLAN PCMCIA device driver's
  * private information.
  */
-static void
-wv_local_show(device *	dev)
+static void wv_local_show(device * dev)
 {
-  net_local *lp;
+	net_local *lp;
 
-  lp = (net_local *)dev->priv;
+	lp = (net_local *) dev->priv;
 
-  printk(KERN_DEBUG "local:");
-  printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
-  printk(" hacr=0x%x,", lp->hacr);
-  printk(" rx_head=0x%x,", lp->rx_head);
-  printk(" rx_last=0x%x,", lp->rx_last);
-  printk(" tx_first_free=0x%x,", lp->tx_first_free);
-  printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
-  printk("\n");
-} /* wv_local_show */
-#endif	/* DEBUG_DEVICE_SHOW */
+	printk(KERN_DEBUG "local:");
+	printk(" tx_n_in_use=%d,", lp->tx_n_in_use);
+	printk(" hacr=0x%x,", lp->hacr);
+	printk(" rx_head=0x%x,", lp->rx_head);
+	printk(" rx_last=0x%x,", lp->rx_last);
+	printk(" tx_first_free=0x%x,", lp->tx_first_free);
+	printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use);
+	printk("\n");
+}				/* wv_local_show */
+#endif				/* DEBUG_DEVICE_SHOW */
 
 #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
 /*------------------------------------------------------------------*/
 /*
  * Dump packet header (and content if necessary) on the screen
  */
-static inline void
-wv_packet_info(u_char *		p,		/* Packet to dump */
-	       int		length,		/* Length of the packet */
-	       char *		msg1,		/* Name of the device */
-	       char *		msg2)		/* Name of the function */
-{
-  int		i;
-  int		maxi;
-
-  printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
-	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
-  printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
-	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+static inline void wv_packet_info(u8 * p,	/* Packet to dump */
+				  int length,	/* Length of the packet */
+				  char *msg1,	/* Name of the device */
+				  char *msg2)
+{				/* Name of the function */
+	int i;
+	int maxi;
+
+	printk(KERN_DEBUG
+	       "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
+	       msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+	printk(KERN_DEBUG
+	       "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
+	       msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
+	       p[13]);
 
 #ifdef DEBUG_PACKET_DUMP
 
-  printk(KERN_DEBUG "data=\"");
+	printk(KERN_DEBUG "data=\"");
 
-  if((maxi = length) > DEBUG_PACKET_DUMP)
-    maxi = DEBUG_PACKET_DUMP;
-  for(i = 14; i < maxi; i++)
-    if(p[i] >= ' ' && p[i] <= '~')
-      printk(" %c", p[i]);
-    else
-      printk("%02X", p[i]);
-  if(maxi < length)
-    printk("..");
-  printk("\"\n");
-  printk(KERN_DEBUG "\n");
-#endif	/* DEBUG_PACKET_DUMP */
+	if ((maxi = length) > DEBUG_PACKET_DUMP)
+		maxi = DEBUG_PACKET_DUMP;
+	for (i = 14; i < maxi; i++)
+		if (p[i] >= ' ' && p[i] <= '~')
+			printk(" %c", p[i]);
+		else
+			printk("%02X", p[i]);
+	if (maxi < length)
+		printk("..");
+	printk("\"\n");
+	printk(KERN_DEBUG "\n");
+#endif				/* DEBUG_PACKET_DUMP */
 }
-#endif	/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
+#endif				/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
 
 /*------------------------------------------------------------------*/
 /*
  * This is the information which is displayed by the driver at startup.
  * There are lots of flags for configuring it to your liking.
  */
-static inline void
-wv_init_info(device *	dev)
+static inline void wv_init_info(device * dev)
 {
-  short		ioaddr = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
-  psa_t		psa;
-  int		i;
+	short ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	psa_t psa;
+	int i;
 
-  /* Read the parameter storage area */
-  psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
+	/* Read the parameter storage area */
+	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
 
 #ifdef DEBUG_PSA_SHOW
-  wv_psa_show(&psa);
+	wv_psa_show(&psa);
 #endif
 #ifdef DEBUG_MMC_SHOW
-  wv_mmc_show(dev);
+	wv_mmc_show(dev);
 #endif
 #ifdef DEBUG_I82586_SHOW
-  wv_cu_show(dev);
+	wv_cu_show(dev);
 #endif
 
 #ifdef DEBUG_BASIC_SHOW
-  /* Now, let's go for the basic stuff. */
-  printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
-  for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
-    printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
-  printk(", IRQ %d", dev->irq);
-
-  /* Print current network ID. */
-  if(psa.psa_nwid_select)
-    printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
-  else
-    printk(", nwid off");
-
-  /* If 2.00 card */
-  if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-    {
-      unsigned short	freq;
-
-      /* Ask the EEPROM to read the frequency from the first area. */
-      fee_read(ioaddr, 0x00, &freq, 1);
-
-      /* Print frequency */
-      printk(", 2.00, %ld", (freq >> 6) + 2400L);
-
-      /* Hack! */
-      if(freq & 0x20)
-	printk(".5");
-    }
-  else
-    {
-      printk(", PC");
-      switch(psa.psa_comp_number)
-	{
-	case PSA_COMP_PC_AT_915:
-	case PSA_COMP_PC_AT_2400:
-	  printk("-AT");
-	  break;
-	case PSA_COMP_PC_MC_915:
-	case PSA_COMP_PC_MC_2400:
-	  printk("-MC");
-	  break;
-	case PSA_COMP_PCMCIA_915:
-	  printk("MCIA");
-	  break;
-	default:
-	  printk("?");
-	}
-      printk(", ");
-      switch (psa.psa_subband)
-	{
-	case PSA_SUBBAND_915:
-	  printk("915");
-	  break;
-	case PSA_SUBBAND_2425:
-	  printk("2425");
-	  break;
-	case PSA_SUBBAND_2460:
-	  printk("2460");
-	  break;
-	case PSA_SUBBAND_2484:
-	  printk("2484");
-	  break;
-	case PSA_SUBBAND_2430_5:
-	  printk("2430.5");
-	  break;
-	default:
-	  printk("?");
+	/* Now, let's go for the basic stuff. */
+	printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
+	for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
+		printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+	printk(", IRQ %d", dev->irq);
+
+	/* Print current network ID. */
+	if (psa.psa_nwid_select)
+		printk(", nwid 0x%02X-%02X", psa.psa_nwid[0],
+		       psa.psa_nwid[1]);
+	else
+		printk(", nwid off");
+
+	/* If 2.00 card */
+	if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+	      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+		unsigned short freq;
+
+		/* Ask the EEPROM to read the frequency from the first area. */
+		fee_read(ioaddr, 0x00, &freq, 1);
+
+		/* Print frequency */
+		printk(", 2.00, %ld", (freq >> 6) + 2400L);
+
+		/* Hack! */
+		if (freq & 0x20)
+			printk(".5");
+	} else {
+		printk(", PC");
+		switch (psa.psa_comp_number) {
+		case PSA_COMP_PC_AT_915:
+		case PSA_COMP_PC_AT_2400:
+			printk("-AT");
+			break;
+		case PSA_COMP_PC_MC_915:
+		case PSA_COMP_PC_MC_2400:
+			printk("-MC");
+			break;
+		case PSA_COMP_PCMCIA_915:
+			printk("MCIA");
+			break;
+		default:
+			printk("?");
+		}
+		printk(", ");
+		switch (psa.psa_subband) {
+		case PSA_SUBBAND_915:
+			printk("915");
+			break;
+		case PSA_SUBBAND_2425:
+			printk("2425");
+			break;
+		case PSA_SUBBAND_2460:
+			printk("2460");
+			break;
+		case PSA_SUBBAND_2484:
+			printk("2484");
+			break;
+		case PSA_SUBBAND_2430_5:
+			printk("2430.5");
+			break;
+		default:
+			printk("?");
+		}
 	}
-    }
 
-  printk(" MHz\n");
-#endif	/* DEBUG_BASIC_SHOW */
+	printk(" MHz\n");
+#endif				/* DEBUG_BASIC_SHOW */
 
 #ifdef DEBUG_VERSION_SHOW
-  /* Print version information */
-  printk(KERN_NOTICE "%s", version);
+	/* Print version information */
+	printk(KERN_NOTICE "%s", version);
 #endif
-} /* wv_init_info */
+}				/* wv_init_info */
 
 /********************* IOCTL, STATS & RECONFIG *********************/
 /*
@@ -1468,14 +1409,13 @@
  * card open or closed.
  * Used when the user read /proc/net/dev
  */
-static en_stats	*
-wavelan_get_stats(device *	dev)
+static en_stats *wavelan_get_stats(device * dev)
 {
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
+	printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
 #endif
 
-  return(&((net_local *) dev->priv)->stats);
+	return (&((net_local *) dev->priv)->stats);
 }
 
 /*------------------------------------------------------------------*/
@@ -1486,76 +1426,70 @@
  * num_addrs > 0	Multicast mode, receive normal and MC packets,
  *			and do best-effort filtering.
  */
-static void
-wavelan_set_multicast_list(device *	dev)
+static void wavelan_set_multicast_list(device * dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
+	net_local *lp = (net_local *) dev->priv;
 
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n",
+	       dev->name);
 #endif
 
 #ifdef DEBUG_IOCTL_INFO
-  printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
-	 dev->name, dev->flags, dev->mc_count);
+	printk(KERN_DEBUG
+	       "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
+	       dev->name, dev->flags, dev->mc_count);
+#endif
+
+	/* Are we asking for promiscuous mode,
+	 * or all multicast addresses (we don't have that!)
+	 * or too many multicast addresses for the hardware filter? */
+	if ((dev->flags & IFF_PROMISC) ||
+	    (dev->flags & IFF_ALLMULTI) ||
+	    (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) {
+		/*
+		 * Enable promiscuous mode: receive all packets.
+		 */
+		if (!lp->promiscuous) {
+			lp->promiscuous = 1;
+			lp->mc_count = 0;
+
+			wv_82586_reconfig(dev);
+
+			/* Tell the kernel that we are doing a really bad job. */
+			dev->flags |= IFF_PROMISC;
+		}
+	} else
+		/* Are there multicast addresses to send? */
+	if (dev->mc_list != (struct dev_mc_list *) NULL) {
+		/*
+		 * Disable promiscuous mode, but receive all packets
+		 * in multicast list
+		 */
+#ifdef MULTICAST_AVOID
+		if (lp->promiscuous || (dev->mc_count != lp->mc_count))
 #endif
+		{
+			lp->promiscuous = 0;
+			lp->mc_count = dev->mc_count;
+
+			wv_82586_reconfig(dev);
+		}
+	} else {
+		/*
+		 * Switch to normal mode: disable promiscuous mode and 
+		 * clear the multicast list.
+		 */
+		if (lp->promiscuous || lp->mc_count == 0) {
+			lp->promiscuous = 0;
+			lp->mc_count = 0;
 
-  /* Are we asking for promiscuous mode,
-   * or all multicast addresses (we don't have that!)
-   * or too many multicast addresses for the hardware filter? */
-  if((dev->flags & IFF_PROMISC) ||
-     (dev->flags & IFF_ALLMULTI) ||
-     (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES))
-    {
-      /*
-       * Enable promiscuous mode: receive all packets.
-       */
-      if(!lp->promiscuous)
-	{
-	  lp->promiscuous = 1;
-	  lp->mc_count = 0;
-
-	  wv_82586_reconfig(dev);
-
-	  /* Tell the kernel that we are doing a really bad job. */
-	  dev->flags |= IFF_PROMISC;
+			wv_82586_reconfig(dev);
+		}
 	}
-    }
-  else
-    /* Are there multicast addresses to send? */
-    if(dev->mc_list != (struct dev_mc_list *) NULL)
-      {
-	/*
-	 * Disable promiscuous mode, but receive all packets
-	 * in multicast list
-	 */
-#ifdef MULTICAST_AVOID
-	if(lp->promiscuous ||
-	   (dev->mc_count != lp->mc_count))
-#endif
-	  {
-	    lp->promiscuous = 0;
-	    lp->mc_count = dev->mc_count;
-
-	    wv_82586_reconfig(dev);
-	  }
-      }
-    else
-      {
-	/*
-	 * Switch to normal mode: disable promiscuous mode and 
-	 * clear the multicast list.
-	 */
-	if(lp->promiscuous || lp->mc_count == 0)
-	  {
-	    lp->promiscuous = 0;
-	    lp->mc_count = 0;
-
-	    wv_82586_reconfig(dev);
-	  }
-      }
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n",
+	       dev->name);
 #endif
 }
 
@@ -1565,23 +1499,21 @@
  * (Note : it was a nice way to test the reconfigure stuff...)
  */
 #ifdef SET_MAC_ADDRESS
-static int
-wavelan_set_mac_address(device *	dev,
-			void *		addr)
+static int wavelan_set_mac_address(device * dev, void *addr)
 {
-  struct sockaddr *	mac = addr;
+	struct sockaddr *mac = addr;
 
-  /* Copy the address. */
-  memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
+	/* Copy the address. */
+	memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
 
-  /* Reconfigure the beast. */
-  wv_82586_reconfig(dev);
+	/* Reconfigure the beast. */
+	wv_82586_reconfig(dev);
 
-  return 0;
+	return 0;
 }
-#endif	/* SET_MAC_ADDRESS */
+#endif				/* SET_MAC_ADDRESS */
 
-#ifdef WIRELESS_EXT	/* if wireless extensions exist in the kernel */
+#ifdef WIRELESS_EXT		/* if wireless extensions exist in the kernel */
 
 /*------------------------------------------------------------------*/
 /*
@@ -1589,232 +1521,215 @@
  * It's a bit complicated and you don't really want to look into it.
  * (called in wavelan_ioctl)
  */
-static inline int
-wv_set_frequency(u_long		ioaddr,	/* I/O port of the card */
-		 iw_freq *	frequency)
+static inline int wv_set_frequency(unsigned long ioaddr,	/* I/O port of the card */
+				   iw_freq * frequency)
 {
-  const int	BAND_NUM = 10;	/* Number of bands */
-  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz */
+	const int BAND_NUM = 10;	/* Number of bands */
+	long freq = 0L;		/* offset to 2.4 GHz in .5 MHz */
 #ifdef DEBUG_IOCTL_INFO
-  int		i;
+	int i;
 #endif
 
-  /* Setting by frequency */
-  /* Theoretically, you may set any frequency between
-   * the two limits with a 0.5 MHz precision. In practice,
-   * I don't want you to have trouble with local regulations.
-   */
-  if((frequency->e == 1) &&
-     (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
-    {
-      freq = ((frequency->m / 10000) - 24000L) / 5;
-    }
-
-  /* Setting by channel (same as wfreqsel) */
-  /* Warning: each channel is 22 MHz wide, so some of the channels
-   * will interfere. */
-  if((frequency->e == 0) &&
-     (frequency->m >= 0) && (frequency->m < BAND_NUM))
-    {
-      /* Get frequency offset. */
-      freq = channel_bands[frequency->m] >> 1;
-    }
-
-  /* Verify that the frequency is allowed. */
-  if(freq != 0L)
-    {
-      u_short	table[10];	/* Authorized frequency table */
-
-      /* Read the frequency table. */
-      fee_read(ioaddr, 0x71, table, 10);
+	/* Setting by frequency */
+	/* Theoretically, you may set any frequency between
+	 * the two limits with a 0.5 MHz precision. In practice,
+	 * I don't want you to have trouble with local regulations.
+	 */
+	if ((frequency->e == 1) &&
+	    (frequency->m >= (int) 2.412e8)
+	    && (frequency->m <= (int) 2.487e8)) {
+		freq = ((frequency->m / 10000) - 24000L) / 5;
+	}
 
-#ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "Frequency table: ");
-      for(i = 0; i < 10; i++)
-	{
-	  printk(" %04X",
-		 table[i]);
+	/* Setting by channel (same as wfreqsel) */
+	/* Warning: each channel is 22 MHz wide, so some of the channels
+	 * will interfere. */
+	if ((frequency->e == 0) &&
+	    (frequency->m >= 0) && (frequency->m < BAND_NUM)) {
+		/* Get frequency offset. */
+		freq = channel_bands[frequency->m] >> 1;
 	}
-      printk("\n");
-#endif
 
-      /* Look in the table to see whether the frequency is allowed. */
-      if(!(table[9 - ((freq - 24) / 16)] &
-	   (1 << ((freq - 24) % 16))))
-	return -EINVAL;		/* not allowed */
-    }
-  else
-    return -EINVAL;
-
-  /* if we get a usable frequency */
-  if(freq != 0L)
-    {
-      unsigned short	area[16];
-      unsigned short	dac[2];
-      unsigned short	area_verify[16];
-      unsigned short	dac_verify[2];
-      /* Corresponding gain (in the power adjust value table)
-       * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
-       * and WCIN062D.DOC, page 6.2.9. */
-      unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
-      int		power_band = 0;		/* Selected band */
-      unsigned short	power_adjust;		/* Correct value */
-
-      /* Search for the gain. */
-      power_band = 0;
-      while((freq > power_limit[power_band]) &&
-	    (power_limit[++power_band] != 0))
-	;
-
-      /* Read the first area. */
-      fee_read(ioaddr, 0x00, area, 16);
-
-      /* Read the DAC. */
-      fee_read(ioaddr, 0x60, dac, 2);
-
-      /* Read the new power adjust value. */
-      fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust, 1);
-      if(power_band & 0x1)
-	power_adjust >>= 8;
-      else
-	power_adjust &= 0xFF;
+	/* Verify that the frequency is allowed. */
+	if (freq != 0L) {
+		u16 table[10];	/* Authorized frequency table */
+
+		/* Read the frequency table. */
+		fee_read(ioaddr, 0x71, table, 10);
 
 #ifdef DEBUG_IOCTL_INFO
-      printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
-      for(i = 0; i < 16; i++)
-	{
-	  printk(" %04X",
-		 area[i]);
-	}
-      printk("\n");
+		printk(KERN_DEBUG "Frequency table: ");
+		for (i = 0; i < 10; i++) {
+			printk(" %04X", table[i]);
+		}
+		printk("\n");
+#endif
+
+		/* Look in the table to see whether the frequency is allowed. */
+		if (!(table[9 - ((freq - 24) / 16)] &
+		      (1 << ((freq - 24) % 16)))) return -EINVAL;	/* not allowed */
+	} else
+		return -EINVAL;
+
+	/* if we get a usable frequency */
+	if (freq != 0L) {
+		unsigned short area[16];
+		unsigned short dac[2];
+		unsigned short area_verify[16];
+		unsigned short dac_verify[2];
+		/* Corresponding gain (in the power adjust value table)
+		 * See AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8
+		 * and WCIN062D.DOC, page 6.2.9. */
+		unsigned short power_limit[] = { 40, 80, 120, 160, 0 };
+		int power_band = 0;	/* Selected band */
+		unsigned short power_adjust;	/* Correct value */
+
+		/* Search for the gain. */
+		power_band = 0;
+		while ((freq > power_limit[power_band]) &&
+		       (power_limit[++power_band] != 0));
+
+		/* Read the first area. */
+		fee_read(ioaddr, 0x00, area, 16);
+
+		/* Read the DAC. */
+		fee_read(ioaddr, 0x60, dac, 2);
+
+		/* Read the new power adjust value. */
+		fee_read(ioaddr, 0x6B - (power_band >> 1), &power_adjust,
+			 1);
+		if (power_band & 0x1)
+			power_adjust >>= 8;
+		else
+			power_adjust &= 0xFF;
+
+#ifdef DEBUG_IOCTL_INFO
+		printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
+		for (i = 0; i < 16; i++) {
+			printk(" %04X", area[i]);
+		}
+		printk("\n");
 
-      printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
-	     dac[0], dac[1]);
+		printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n",
+		       dac[0], dac[1]);
 #endif
 
-      /* Frequency offset (for info only) */
-      area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
+		/* Frequency offset (for info only) */
+		area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
 
-      /* Receiver Principle main divider coefficient */
-      area[3] = (freq >> 1) + 2400L - 352L;
-      area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+		/* Receiver Principle main divider coefficient */
+		area[3] = (freq >> 1) + 2400L - 352L;
+		area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
 
-      /* Transmitter Main divider coefficient */
-      area[13] = (freq >> 1) + 2400L;
-      area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+		/* Transmitter Main divider coefficient */
+		area[13] = (freq >> 1) + 2400L;
+		area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
 
-      /* Other parts of the area are flags, bit streams or unused. */
+		/* Other parts of the area are flags, bit streams or unused. */
 
-      /* Set the value in the DAC. */
-      dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
-      dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
+		/* Set the value in the DAC. */
+		dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
+		dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
 
-      /* Write the first area. */
-      fee_write(ioaddr, 0x00,
-		area, 16);
+		/* Write the first area. */
+		fee_write(ioaddr, 0x00, area, 16);
 
-      /* Write the DAC. */
-      fee_write(ioaddr, 0x60,
-		dac, 2);
+		/* Write the DAC. */
+		fee_write(ioaddr, 0x60, dac, 2);
 
-      /* We now should verify here that the writing of the EEPROM went OK. */
+		/* We now should verify here that the writing of the EEPROM went OK. */
 
-      /* Reread the first area. */
-      fee_read(ioaddr, 0x00, area_verify, 16);
+		/* Reread the first area. */
+		fee_read(ioaddr, 0x00, area_verify, 16);
 
-      /* Reread the DAC. */
-      fee_read(ioaddr, 0x60, dac_verify, 2);
+		/* Reread the DAC. */
+		fee_read(ioaddr, 0x60, dac_verify, 2);
 
-      /* Compare. */
-      if(memcmp(area, area_verify, 16 * 2) ||
-	 memcmp(dac, dac_verify, 2 * 2))
-	{
+		/* Compare. */
+		if (memcmp(area, area_verify, 16 * 2) ||
+		    memcmp(dac, dac_verify, 2 * 2)) {
 #ifdef DEBUG_IOCTL_ERROR
-	  printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
+			printk(KERN_INFO
+			       "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n");
 #endif
-	  return -EOPNOTSUPP;
-	}
+			return -EOPNOTSUPP;
+		}
 
-      /* We must download the frequency parameters to the
-       * synthesizers (from the EEPROM - area 1)
-       * Note: as the EEPROM is automatically decremented, we set the end
-       * if the area... */
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
-	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
-
-      /* Wait until the download is finished. */
-      fee_wait(ioaddr, 100, 100);
-
-      /* We must now download the power adjust value (gain) to
-       * the synthesizers (from the EEPROM - area 7 - DAC). */
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
-      mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
-	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+		/* We must download the frequency parameters to the
+		 * synthesizers (from the EEPROM - area 1)
+		 * Note: as the EEPROM is automatically decremented, we set the end
+		 * if the area... */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F);
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+		/* Wait until the download is finished. */
+		fee_wait(ioaddr, 100, 100);
+
+		/* We must now download the power adjust value (gain) to
+		 * the synthesizers (from the EEPROM - area 7 - DAC). */
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61);
+		mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl),
+			MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
 
-      /* Wait for the download to finish. */
-      fee_wait(ioaddr, 100, 100);
+		/* Wait for the download to finish. */
+		fee_wait(ioaddr, 100, 100);
 
 #ifdef DEBUG_IOCTL_INFO
-      /* Verification of what we have done */
+		/* Verification of what we have done */
 
-      printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
-      for(i = 0; i < 16; i++)
-	{
-	  printk(" %04X",
-		 area_verify[i]);
-	}
-      printk("\n");
+		printk(KERN_DEBUG "WaveLAN EEPROM Area 1: ");
+		for (i = 0; i < 16; i++) {
+			printk(" %04X", area_verify[i]);
+		}
+		printk("\n");
 
-      printk(KERN_DEBUG "WaveLAN EEPROM DAC:  %04X %04X\n",
-	     dac_verify[0], dac_verify[1]);
+		printk(KERN_DEBUG "WaveLAN EEPROM DAC:  %04X %04X\n",
+		       dac_verify[0], dac_verify[1]);
 #endif
 
-      return 0;
-    }
-  else
-    return -EINVAL;		/* Bah, never get there... */
+		return 0;
+	} else
+		return -EINVAL;	/* Bah, never get there... */
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Give the list of available frequencies.
  */
-static inline int
-wv_frequency_list(u_long	ioaddr,	/* I/O port of the card */
-		  iw_freq *	list,	/* List of frequencies to fill */
-		  int		max)	/* Maximum number of frequencies */
-{
-  u_short	table[10];	/* Authorized frequency table */
-  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
-  int		i;		/* index in the table */
-  int		c = 0;		/* Channel number */
-
-  /* Read the frequency table. */
-  fee_read(ioaddr, 0x71 /* frequency table */, table, 10);
-
-  /* Check all frequencies. */
-  i = 0;
-  for(freq = 0; freq < 150; freq++)
-    /* Look in the table if the frequency is allowed */
-    if(table[9 - (freq / 16)] & (1 << (freq % 16)))
-      {
-	/* Compute approximate channel number */
-	while((((channel_bands[c] >> 1) - 24) < freq) &&
-	      (c < NELS(channel_bands)))
-	  c++;
-	list[i].i = c;	/* Set the list index */
-
-	/* put in the list */
-	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
-	list[i++].e = 1;
-
-	/* Check number. */
-	if(i >= max)
-	  return(i);
-      }
+static inline int wv_frequency_list(unsigned long ioaddr,	/* I/O port of the card */
+				    iw_freq * list,	/* List of frequencies to fill */
+				    int max)
+{				/* Maximum number of frequencies */
+	u16 table[10];	/* Authorized frequency table */
+	long freq = 0L;		/* offset to 2.4 GHz in .5 MHz + 12 MHz */
+	int i;			/* index in the table */
+	int c = 0;		/* Channel number */
+
+	/* Read the frequency table. */
+	fee_read(ioaddr, 0x71 /* frequency table */ , table, 10);
+
+	/* Check all frequencies. */
+	i = 0;
+	for (freq = 0; freq < 150; freq++)
+		/* Look in the table if the frequency is allowed */
+		if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
+			/* Compute approximate channel number */
+			while ((((channel_bands[c] >> 1) - 24) < freq) &&
+			       (c < NELS(channel_bands)))
+				c++;
+			list[i].i = c;	/* Set the list index */
+
+			/* put in the list */
+			list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
+			list[i++].e = 1;
+
+			/* Check number. */
+			if (i >= max)
+				return (i);
+		}
 
-  return(i);
+	return (i);
 }
 
 #ifdef WIRELESS_SPY
@@ -1824,27 +1739,24 @@
  * address with our list, and if they match, get the statistics.
  * Sorry, but this function really needs the wireless extensions.
  */
-static inline void
-wl_spy_gather(device *	dev,
-	      u_char *	mac,		/* MAC address */
-	      u_char *	stats)		/* Statistics to gather */
-{
-  net_local *	lp = (net_local *) dev->priv;
-  int		i;
-
-  /* Check all addresses. */
-  for(i = 0; i < lp->spy_number; i++)
-    /* If match */
-    if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
-      {
-	/* Update statistics */
-	lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
-	lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
-	lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
-	lp->spy_stat[i].updated = 0x7;
-      }
+static inline void wl_spy_gather(device * dev, u8 * mac,	/* MAC address */
+				 u8 * stats)
+{				/* Statistics to gather */
+	net_local *lp = (net_local *) dev->priv;
+	int i;
+
+	/* Check all addresses. */
+	for (i = 0; i < lp->spy_number; i++)
+		/* If match */
+		if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) {
+			/* Update statistics */
+			lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
+			lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
+			lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
+			lp->spy_stat[i].updated = 0x7;
+		}
 }
-#endif	/* WIRELESS_SPY */
+#endif				/* WIRELESS_SPY */
 
 #ifdef HISTOGRAM
 /*------------------------------------------------------------------*/
@@ -1856,494 +1768,516 @@
  * With this histogram you may detect if one WaveLAN is really weak,
  * or you may also calculate the mean and standard deviation of the level.
  */
-static inline void
-wl_his_gather(device *	dev,
-	      u_char *	stats)		/* Statistics to gather */
-{
-  net_local *	lp = (net_local *) dev->priv;
-  u_char	level = stats[0] & MMR_SIGNAL_LVL;
-  int		i;
-
-  /* Find the correct interval. */
-  i = 0;
-  while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
-    ;
+static inline void wl_his_gather(device * dev, u8 * stats)
+{				/* Statistics to gather */
+	net_local *lp = (net_local *) dev->priv;
+	u8 level = stats[0] & MMR_SIGNAL_LVL;
+	int i;
+
+	/* Find the correct interval. */
+	i = 0;
+	while ((i < (lp->his_number - 1))
+	       && (level >= lp->his_range[i++]));
 
-  /* Increment interval counter. */
-  (lp->his_sum[i])++;
+	/* Increment interval counter. */
+	(lp->his_sum[i])++;
 }
-#endif	/* HISTOGRAM */
+#endif				/* HISTOGRAM */
 
 /*------------------------------------------------------------------*/
 /*
  * Perform ioctl for configuration and information.
  * It is here that the wireless extensions are treated (iwconfig).
  */
-static int
-wavelan_ioctl(struct net_device *	dev,	/* device on which the ioctl is applied */
-	      struct ifreq *	rq,	/* data passed */
-	      int		cmd)	/* ioctl number */
-{
-  u_long		ioaddr = dev->base_addr;
-  net_local *		lp = (net_local *)dev->priv;	/* lp is not unused */
-  struct iwreq *	wrq = (struct iwreq *) rq;
-  psa_t			psa;
-  mm_t			m;
-  unsigned long		x;
-  int			ret = 0;
+static int wavelan_ioctl(struct net_device *dev,	/* device on which the ioctl is applied */
+			 struct ifreq *rq,	/* data passed */
+			 int cmd)
+{				/* ioctl number */
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	struct iwreq *wrq = (struct iwreq *) rq;
+	psa_t psa;
+	mm_t m;
+	unsigned long flags;
+	int ret = 0;
 
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
+	printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
+	       cmd);
 #endif
 
-  /* Disable interrupts and save flags. */
-  x = wv_splhi();
-
-  /* Look what is the request */
-  switch(cmd)
-    {
-      /* --------------- WIRELESS EXTENSIONS --------------- */
-
-    case SIOCGIWNAME:
-      strcpy(wrq->u.name, "WaveLAN");
-      break;
-
-    case SIOCSIWNWID:
-      /* Set NWID in WaveLAN. */
-      if(!wrq->u.nwid.disabled)
-	{
-	  /* Set NWID in psa */
-	  psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
-	  psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
-	  psa.psa_nwid_select = 0x01;
-	  psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
-		    (unsigned char *)psa.psa_nwid, 3);
-
-	  /* Set NWID in mmc. */
-	  m.w.mmw_netw_id_l = psa.psa_nwid[1];
-	  m.w.mmw_netw_id_h = psa.psa_nwid[0];
-	  mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m,
-		    (unsigned char *)&m.w.mmw_netw_id_l, 2);
-	  mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
-	}
-      else
-	{
-	  /* Disable NWID in the psa. */
-	  psa.psa_nwid_select = 0x00;
-	  psa_write(ioaddr, lp->hacr,
-		    (char *)&psa.psa_nwid_select - (char *)&psa,
-		    (unsigned char *)&psa.psa_nwid_select, 1);
-
-	  /* Disable NWID in the mmc (no filtering). */
-	  mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
-	}
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev, ioaddr, lp->hacr);
-      break;
-
-    case SIOCGIWNWID:
-      /* Read the NWID. */
-      psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
-	       (unsigned char *)psa.psa_nwid, 3);
-      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
-      wrq->u.nwid.fixed = 1;	/* Superfluous */
-      break;
-
-    case SIOCSIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
-      if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-	ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
-      else
-	ret = -EOPNOTSUPP;
-      break;
-
-    case SIOCGIWFREQ:
-      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
-       * Does it work for everybody, especially old cards? */
-      if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-	{
-	  unsigned short	freq;
-
-	  /* Ask the EEPROM to read the frequency from the first area. */
-	  fee_read(ioaddr, 0x00, &freq, 1);
-	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
-	  wrq->u.freq.e = 1;
-	}
-      else
-	{
-	  psa_read(ioaddr, lp->hacr, (char *)&psa.psa_subband - (char *)&psa,
-		   (unsigned char *)&psa.psa_subband, 1);
-
-	  if(psa.psa_subband <= 4)
-	    {
-	      wrq->u.freq.m = fixed_bands[psa.psa_subband];
-	      wrq->u.freq.e = (psa.psa_subband != 0);
-	    }
-	  else
-	    ret = -EOPNOTSUPP;
-	}
-      break;
-
-    case SIOCSIWSENS:
-      /* Set the level threshold. */
-      /* We should complain loudly if wrq->u.sens.fixed = 0, because we
-       * can't set auto mode... */
-      psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
-      psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
-	       (unsigned char *) &psa.psa_thr_pre_set, 1);
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev, ioaddr, lp->hacr);
-      mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
-      break;
-
-    case SIOCGIWSENS:
-      /* Read the level threshold. */
-      psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
-	       (unsigned char *) &psa.psa_thr_pre_set, 1);
-      wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
-      wrq->u.sens.fixed = 1;
-      break;
-
-    case SIOCSIWENCODE:
-      /* Set encryption key */
-      if(!mmc_encr(ioaddr))
-	{
-	  ret = -EOPNOTSUPP;
-	  break;
-	}
-
-      /* Basic checking... */
-      if(wrq->u.encoding.pointer != (caddr_t) 0)
-	{
-	  /* Check the size of the key */
-	  if(wrq->u.encoding.length != 8)
-	    {
-	      ret = -EINVAL;
-	      break;
-	    }
-
-	  /* Copy the key in the driver */
-	  if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
-			    wrq->u.encoding.length))
-	    {
-	      ret = -EFAULT;
-	      break;
-	    }
-
-	  psa.psa_encryption_select = 1;
-	  psa_write(ioaddr, lp->hacr,
-		    (char *) &psa.psa_encryption_select - (char *) &psa,
-		    (unsigned char *) &psa.psa_encryption_select, 8+1);
-
-	  mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
-		  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
-	  mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
-		    (unsigned char *) &psa.psa_encryption_key, 8);
-	}
-
-      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
-	{	/* disable encryption */
-	  psa.psa_encryption_select = 0;
-	  psa_write(ioaddr, lp->hacr,
-		    (char *) &psa.psa_encryption_select - (char *) &psa,
-		    (unsigned char *) &psa.psa_encryption_select, 1);
-
-	  mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
-	}
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev, ioaddr, lp->hacr);
-      break;
-
-    case SIOCGIWENCODE:
-      /* Read the encryption key */
-      if(!mmc_encr(ioaddr))
-	{
-	  ret = -EOPNOTSUPP;
-	  break;
-	}
-
-      /* only super-user can see encryption key */
-      if(!suser())
-	{
-	  ret = -EPERM;
-	  break;
-	}
-
-      /* Basic checking... */
-      if(wrq->u.encoding.pointer != (caddr_t) 0)
-	{
-	  /* Verify the user buffer */
-	  ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8);
-	  if(ret)
-	    break;
-
-	  psa_read(ioaddr, lp->hacr,
-		   (char *) &psa.psa_encryption_select - (char *) &psa,
-		   (unsigned char *) &psa.psa_encryption_select, 1+8);
-
-	  /* encryption is enabled ? */
-	  if(psa.psa_encryption_select)
-	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
-	  else
-	    wrq->u.encoding.flags = IW_ENCODE_DISABLED;
-	  wrq->u.encoding.flags |= mmc_encr(ioaddr);
-
-	  /* Copy the key to the user buffer */
-	  wrq->u.encoding.length = 8;
-	  if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
-	    ret = -EFAULT;
-	}
-      break;
-
-    case SIOCGIWRANGE:
-      /* basic checking */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-	{
-	  struct iw_range	range;
-
-	  /* Set the length (useless:  it's constant). */
-	  wrq->u.data.length = sizeof(struct iw_range);
-
-	  /* Set information in the range struct.  */
-	  range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
-	  range.min_nwid = 0x0000;
-	  range.max_nwid = 0xFFFF;
-
-	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
-	  if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-	       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-	    {
-	      range.num_channels = 10;
-	      range.num_frequency = wv_frequency_list(ioaddr, range.freq,
+	/* Disable interrupts and save flags. */
+	save_flags(flags);
+	cli();
+	/* FIXME: can't copy*user when cli this is broken! */
+	
+	/* Look what is the request */
+	switch (cmd) {
+		/* --------------- WIRELESS EXTENSIONS --------------- */
+
+	case SIOCGIWNAME:
+		strcpy(wrq->u.name, "WaveLAN");
+		break;
+
+	case SIOCSIWNWID:
+		/* Set NWID in WaveLAN. */
+		if (!wrq->u.nwid.disabled) {
+			/* Set NWID in psa */
+			psa.psa_nwid[0] =
+			    (wrq->u.nwid.value & 0xFF00) >> 8;
+			psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+			psa.psa_nwid_select = 0x01;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) psa.psa_nwid - (char *) &psa,
+				  (unsigned char *) psa.psa_nwid, 3);
+
+			/* Set NWID in mmc. */
+			m.w.mmw_netw_id_l = psa.psa_nwid[1];
+			m.w.mmw_netw_id_h = psa.psa_nwid[0];
+			mmc_write(ioaddr,
+				  (char *) &m.w.mmw_netw_id_l -
+				  (char *) &m,
+				  (unsigned char *) &m.w.mmw_netw_id_l, 2);
+			mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
+		} else {
+			/* Disable NWID in the psa. */
+			psa.psa_nwid_select = 0x00;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) &psa.psa_nwid_select -
+				  (char *) &psa,
+				  (unsigned char *) &psa.psa_nwid_select,
+				  1);
+
+			/* Disable NWID in the mmc (no filtering). */
+			mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel),
+				MMW_LOOPT_SEL_DIS_NWID);
+		}
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		break;
+
+	case SIOCGIWNWID:
+		/* Read the NWID. */
+		psa_read(ioaddr, lp->hacr,
+			 (char *) psa.psa_nwid - (char *) &psa,
+			 (unsigned char *) psa.psa_nwid, 3);
+		wrq->u.nwid.value =
+		    (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+		wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+		wrq->u.nwid.fixed = 1;	/* Superfluous */
+		break;
+
+	case SIOCSIWFREQ:
+		/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+		if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+		      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+			ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
+		else
+			ret = -EOPNOTSUPP;
+		break;
+
+	case SIOCGIWFREQ:
+		/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
+		 * Does it work for everybody, especially old cards? */
+		if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+		      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+			unsigned short freq;
+
+			/* Ask the EEPROM to read the frequency from the first area. */
+			fee_read(ioaddr, 0x00, &freq, 1);
+			wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+			wrq->u.freq.e = 1;
+		} else {
+			psa_read(ioaddr, lp->hacr,
+				 (char *) &psa.psa_subband - (char *) &psa,
+				 (unsigned char *) &psa.psa_subband, 1);
+
+			if (psa.psa_subband <= 4) {
+				wrq->u.freq.m =
+				    fixed_bands[psa.psa_subband];
+				wrq->u.freq.e = (psa.psa_subband != 0);
+			} else
+				ret = -EOPNOTSUPP;
+		}
+		break;
+
+	case SIOCSIWSENS:
+		/* Set the level threshold. */
+		/* We should complain loudly if wrq->u.sens.fixed = 0, because we
+		 * can't set auto mode... */
+		psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_thr_pre_set - (char *) &psa,
+			  (unsigned char *) &psa.psa_thr_pre_set, 1);
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set),
+			psa.psa_thr_pre_set);
+		break;
+
+	case SIOCGIWSENS:
+		/* Read the level threshold. */
+		psa_read(ioaddr, lp->hacr,
+			 (char *) &psa.psa_thr_pre_set - (char *) &psa,
+			 (unsigned char *) &psa.psa_thr_pre_set, 1);
+		wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
+		wrq->u.sens.fixed = 1;
+		break;
+
+	case SIOCSIWENCODE:
+		/* Set encryption key */
+		if (!mmc_encr(ioaddr)) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		/* Basic checking... */
+		if (wrq->u.encoding.pointer != (caddr_t) 0) {
+			/* Check the size of the key */
+			if (wrq->u.encoding.length != 8) {
+				ret = -EINVAL;
+				break;
+			}
+
+			/* Copy the key in the driver */
+			if (copy_from_user
+			    (psa.psa_encryption_key,
+			     wrq->u.encoding.pointer,
+			     wrq->u.encoding.length)) {
+				ret = -EFAULT;
+				break;
+			}
+
+			psa.psa_encryption_select = 1;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) &psa.psa_encryption_select -
+				  (char *) &psa,
+				  (unsigned char *) &psa.
+				  psa_encryption_select, 8 + 1);
+
+			mmc_out(ioaddr, mmwoff(0, mmw_encr_enable),
+				MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+			mmc_write(ioaddr, mmwoff(0, mmw_encr_key),
+				  (unsigned char *) &psa.
+				  psa_encryption_key, 8);
+		}
+
+		if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) {	/* disable encryption */
+			psa.psa_encryption_select = 0;
+			psa_write(ioaddr, lp->hacr,
+				  (char *) &psa.psa_encryption_select -
+				  (char *) &psa,
+				  (unsigned char *) &psa.
+				  psa_encryption_select, 1);
+
+			mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
+		}
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		break;
+
+	case SIOCGIWENCODE:
+		/* Read the encryption key */
+		if (!mmc_encr(ioaddr)) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		/* only super-user can see encryption key */
+		if (!suser()) {
+			ret = -EPERM;
+			break;
+		}
+
+		/* Basic checking... */
+		if (wrq->u.encoding.pointer != (caddr_t) 0) {
+			/* Verify the user buffer */
+			ret =
+			    verify_area(VERIFY_WRITE,
+					wrq->u.encoding.pointer, 8);
+			if (ret)
+				break;
+
+			psa_read(ioaddr, lp->hacr,
+				 (char *) &psa.psa_encryption_select -
+				 (char *) &psa,
+				 (unsigned char *) &psa.
+				 psa_encryption_select, 1 + 8);
+
+			/* encryption is enabled ? */
+			if (psa.psa_encryption_select)
+				wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+			else
+				wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+			wrq->u.encoding.flags |= mmc_encr(ioaddr);
+
+			/* Copy the key to the user buffer */
+			wrq->u.encoding.length = 8;
+			if (copy_to_user
+			    (wrq->u.encoding.pointer,
+			     psa.psa_encryption_key, 8)) ret = -EFAULT;
+		}
+		break;
+
+	case SIOCGIWRANGE:
+		/* basic checking */
+		if (wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_range range;
+
+			/* Set the length (useless:  it's constant). */
+			wrq->u.data.length = sizeof(struct iw_range);
+
+			/* Set information in the range struct.  */
+			range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
+			range.min_nwid = 0x0000;
+			range.max_nwid = 0xFFFF;
+
+			/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
+			if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+			      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+				range.num_channels = 10;
+				range.num_frequency =
+				    wv_frequency_list(ioaddr, range.freq,
 						      IW_MAX_FREQUENCIES);
-	    }
-	  else
-	    range.num_channels = range.num_frequency = 0;
-
-	  range.sensitivity = 0x3F;
-	  range.max_qual.qual = MMR_SGNL_QUAL;
-	  range.max_qual.level = MMR_SIGNAL_LVL;
-	  range.max_qual.noise = MMR_SILENCE_LVL;
-
-	  range.num_bitrates = 1;
-	  range.bitrate[0] = 2000000;	/* 2 Mb/s */
-
-	  /* Encryption supported ? */
-	  if(mmc_encr(ioaddr))
-	    {
-	      range.encoding_size[0] = 8;	/* DES = 64 bits key */
-	      range.num_encoding_sizes = 1;
-	      range.max_encoding_tokens = 1;	/* Only one key possible */
-	    }
-	  else
-	    {
-	      range.num_encoding_sizes = 0;
-	      range.max_encoding_tokens = 0;
-	    }
-
-	  /* Copy structure to the user buffer. */
-	  if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
-	  	ret = -EFAULT;
-	}
-      break;
-
-    case SIOCGIWPRIV:
-      /* Basic checking */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-	{
-	  struct iw_priv_args	priv[] =
-	  {	/* cmd,		set_args,	get_args,	name */
-	    { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
-	    { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
-
-	    { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,	0, "sethisto" },
-	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
-	  };
-
-	  /* Set the number of available ioctls. */
-	  wrq->u.data.length = 4;
-
-	  /* Copy structure to the user buffer. */
-	  if (copy_to_user(wrq->u.data.pointer, (u_char *) priv, sizeof(priv)))
-	  	ret = -EFAULT;
-	}
-      break;
+			} else
+				range.num_channels = range.num_frequency =
+				    0;
+
+			range.sensitivity = 0x3F;
+			range.max_qual.qual = MMR_SGNL_QUAL;
+			range.max_qual.level = MMR_SIGNAL_LVL;
+			range.max_qual.noise = MMR_SILENCE_LVL;
+
+			range.num_bitrates = 1;
+			range.bitrate[0] = 2000000;	/* 2 Mb/s */
+
+			/* Encryption supported ? */
+			if (mmc_encr(ioaddr)) {
+				range.encoding_size[0] = 8;	/* DES = 64 bits key */
+				range.num_encoding_sizes = 1;
+				range.max_encoding_tokens = 1;	/* Only one key possible */
+			} else {
+				range.num_encoding_sizes = 0;
+				range.max_encoding_tokens = 0;
+			}
+
+			/* Copy structure to the user buffer. */
+			if (copy_to_user
+			    (wrq->u.data.pointer, &range,
+			     sizeof(struct iw_range))) ret = -EFAULT;
+		}
+		break;
+
+	case SIOCGIWPRIV:
+		/* Basic checking */
+		if (wrq->u.data.pointer != (caddr_t) 0) {
+			struct iw_priv_args priv[] = {	/* cmd,         set_args,       get_args,       name */
+				
+				    {SIOCSIPQTHR,
+				 IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
+				     1, 0, "setqualthr"},
+				{SIOCGIPQTHR, 0,
+				 IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
+				 1, "getqualthr"},
+
+				
+				    {SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,
+				 0, "sethisto"},
+				{SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16,
+				 "gethisto"},
+			};
+
+			/* Set the number of available ioctls. */
+			wrq->u.data.length = 4;
+
+			/* Copy structure to the user buffer. */
+			if (copy_to_user
+			    (wrq->u.data.pointer, (u8 *) priv,
+			     sizeof(priv))) ret = -EFAULT;
+		}
+		break;
 
 #ifdef WIRELESS_SPY
-    case SIOCSIWSPY:
-      /* Set the spy list */
-
-      /* Check the number of addresses. */
-      if(wrq->u.data.length > IW_MAX_SPY)
-	{
-	  ret = -E2BIG;
-	  break;
-	}
-      lp->spy_number = wrq->u.data.length;
-
-      /* Are there are addresses to copy? */
-      if(lp->spy_number > 0)
-	{
-	  struct sockaddr	address[IW_MAX_SPY];
-	  int			i;
-
-	  /* Copy addresses to the driver. */
-	  if (copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * lp->spy_number)) {
-	  	ret = -EFAULT;
-	  	break;
-	  }
-
-	  /* Copy addresses to the lp structure. */
-	  for(i = 0; i < lp->spy_number; i++)
-	    {
-	      memcpy(lp->spy_address[i], address[i].sa_data,
-		     WAVELAN_ADDR_SIZE);
-	    }
+	case SIOCSIWSPY:
+		/* Set the spy list */
 
-	  /* Reset structure. */
-	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+		/* Check the number of addresses. */
+		if (wrq->u.data.length > IW_MAX_SPY) {
+			ret = -E2BIG;
+			break;
+		}
+		lp->spy_number = wrq->u.data.length;
+
+		/* Are there are addresses to copy? */
+		if (lp->spy_number > 0) {
+			struct sockaddr address[IW_MAX_SPY];
+			int i;
+
+			/* Copy addresses to the driver. */
+			if (copy_from_user
+			    (address, wrq->u.data.pointer,
+			     sizeof(struct sockaddr) * lp->spy_number)) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Copy addresses to the lp structure. */
+			for (i = 0; i < lp->spy_number; i++) {
+				memcpy(lp->spy_address[i],
+				       address[i].sa_data,
+				       WAVELAN_ADDR_SIZE);
+			}
+
+			/* Reset structure. */
+			memset(lp->spy_stat, 0x00,
+			       sizeof(iw_qual) * IW_MAX_SPY);
 
 #ifdef DEBUG_IOCTL_INFO
-	  printk(KERN_DEBUG "SetSpy:  set of new addresses is: \n");
-	  for(i = 0; i < wrq->u.data.length; i++)
-	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n",
-		   lp->spy_address[i][0],
-		   lp->spy_address[i][1],
-		   lp->spy_address[i][2],
-		   lp->spy_address[i][3],
-		   lp->spy_address[i][4],
-		   lp->spy_address[i][5]);
-#endif	/* DEBUG_IOCTL_INFO */
-	}
-
-      break;
-
-    case SIOCGIWSPY:
-      /* Get the spy list and spy stats. */
-
-      /* Set the number of addresses */
-      wrq->u.data.length = lp->spy_number;
-
-      /* Does the user want to have the addresses back? */
-      if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
-	{
-	  struct sockaddr	address[IW_MAX_SPY];
-	  int			i;
-
-	  /* Copy addresses from the lp structure. */
-	  for(i = 0; i < lp->spy_number; i++)
-	    {
-	      memcpy(address[i].sa_data, lp->spy_address[i],
-		     WAVELAN_ADDR_SIZE);
-	      address[i].sa_family = AF_UNIX;
-	    }
-
-	  /* Copy addresses to the user buffer. */
-	  if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * lp->spy_number)) {
-	  	ret = -EFAULT;
-	  	break;
-	  }
-	  	
-	  /* Copy stats to the user buffer (just after). */
-	  if (copy_to_user(wrq->u.data.pointer +
-		       (sizeof(struct sockaddr) * lp->spy_number),
-		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number)) {
-		       		ret = -EFAULT;
-		       		break;
-	  }
-
-	  /* Reset updated flags. */
-	  for(i = 0; i < lp->spy_number; i++)
-	    lp->spy_stat[i].updated = 0x0;
-	}	/* if(pointer != NULL) */
-
-      break;
-#endif	/* WIRELESS_SPY */
-
-      /* ------------------ PRIVATE IOCTL ------------------ */
-
-    case SIOCSIPQTHR:
-      if(!suser())
-        {
-	  ret = -EPERM;
-	  break;
-	}
-      psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
-      psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
-	       (unsigned char *)&psa.psa_quality_thr, 1);
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev, ioaddr, lp->hacr);
-      mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
-      break;
-
-    case SIOCGIPQTHR:
-      psa_read(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
-	       (unsigned char *)&psa.psa_quality_thr, 1);
-      *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
-      break;
+			printk(KERN_DEBUG
+			       "SetSpy:  set of new addresses is: \n");
+			for (i = 0; i < wrq->u.data.length; i++)
+				printk(KERN_DEBUG
+				       "%02X:%02X:%02X:%02X:%02X:%02X \n",
+				       lp->spy_address[i][0],
+				       lp->spy_address[i][1],
+				       lp->spy_address[i][2],
+				       lp->spy_address[i][3],
+				       lp->spy_address[i][4],
+				       lp->spy_address[i][5]);
+#endif				/* DEBUG_IOCTL_INFO */
+		}
+
+		break;
+
+	case SIOCGIWSPY:
+		/* Get the spy list and spy stats. */
+
+		/* Set the number of addresses */
+		wrq->u.data.length = lp->spy_number;
+
+		/* Does the user want to have the addresses back? */
+		if ((lp->spy_number > 0)
+		    && (wrq->u.data.pointer != (caddr_t) 0)) {
+			struct sockaddr address[IW_MAX_SPY];
+			int i;
+
+			/* Copy addresses from the lp structure. */
+			for (i = 0; i < lp->spy_number; i++) {
+				memcpy(address[i].sa_data,
+				       lp->spy_address[i],
+				       WAVELAN_ADDR_SIZE);
+				address[i].sa_family = AF_UNIX;
+			}
+
+			/* Copy addresses to the user buffer. */
+			if (copy_to_user
+			    (wrq->u.data.pointer, address,
+			     sizeof(struct sockaddr) * lp->spy_number)) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Copy stats to the user buffer (just after). */
+			if (copy_to_user(wrq->u.data.pointer +
+					 (sizeof(struct sockaddr) *
+					  lp->spy_number), lp->spy_stat,
+					 sizeof(iw_qual) * lp->spy_number)) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Reset updated flags. */
+			for (i = 0; i < lp->spy_number; i++)
+				lp->spy_stat[i].updated = 0x0;
+		}
+		/* if(pointer != NULL) */
+		break;
+#endif				/* WIRELESS_SPY */
+
+		/* ------------------ PRIVATE IOCTL ------------------ */
+
+	case SIOCSIPQTHR:
+		if (!suser()) {
+			ret = -EPERM;
+			break;
+		}
+		psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_quality_thr - (char *) &psa,
+			  (unsigned char *) &psa.psa_quality_thr, 1);
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+		mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
+			psa.psa_quality_thr);
+		break;
+
+	case SIOCGIPQTHR:
+		psa_read(ioaddr, lp->hacr,
+			 (char *) &psa.psa_quality_thr - (char *) &psa,
+			 (unsigned char *) &psa.psa_quality_thr, 1);
+		*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+		break;
 
 #ifdef HISTOGRAM
-    case SIOCSIPHISTO:
-      /* Verify that the user is root. */
-      if(!suser())
-        {
-	  ret = -EPERM;
-	  break;
-	}
-
-      /* Check the number of intervals. */
-      if(wrq->u.data.length > 16)
-	{
-	  ret = -E2BIG;
-	  break;
-	}
-      lp->his_number = wrq->u.data.length;
+	case SIOCSIPHISTO:
+		/* Verify that the user is root. */
+		if (!suser()) {
+			ret = -EPERM;
+			break;
+		}
+
+		/* Check the number of intervals. */
+		if (wrq->u.data.length > 16) {
+			ret = -E2BIG;
+			break;
+		}
+		lp->his_number = wrq->u.data.length;
+
+		/* Are there addresses to copy? */
+		if (lp->his_number > 0) {
+			/* Copy interval ranges to the driver */
+			if (copy_from_user
+			    (lp->his_range, wrq->u.data.pointer,
+			     sizeof(char) * lp->his_number)) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/* Reset structure. */
+			memset(lp->his_sum, 0x00, sizeof(long) * 16);
+		}
+		break;
+
+	case SIOCGIPHISTO:
+		/* Set the number of intervals. */
+		wrq->u.data.length = lp->his_number;
+
+		/* Give back the distribution statistics */
+		if ((lp->his_number > 0)
+		    && (wrq->u.data.pointer != (caddr_t) 0)) {
+			/* Copy data to the user buffer. */
+			if (copy_to_user
+			    (wrq->u.data.pointer, lp->his_sum,
+			     sizeof(long) * lp->his_number))
+				ret = -EFAULT;
+
+		}		/* if(pointer != NULL) */
+		break;
+#endif				/* HISTOGRAM */
 
-      /* Are there addresses to copy? */
-      if(lp->his_number > 0)
-	{
-	  /* Copy interval ranges to the driver */
-	  if (copy_from_user(lp->his_range, wrq->u.data.pointer, sizeof(char) * lp->his_number)) {
-	  	ret = -EFAULT;
-	  	break;
-	  }
-
-	  /* Reset structure. */
-	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
-	}
-      break;
-
-    case SIOCGIPHISTO:
-      /* Set the number of intervals. */
-      wrq->u.data.length = lp->his_number;
+		/* ------------------- OTHER IOCTL ------------------- */
 
-      /* Give back the distribution statistics */
-      if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
-	{
-	  /* Copy data to the user buffer. */
-	  if (copy_to_user(wrq->u.data.pointer, lp->his_sum, sizeof(long) * lp->his_number)) 
-			ret = -EFAULT;
-			
-	}	/* if(pointer != NULL) */
-      break;
-#endif	/* HISTOGRAM */
-
-      /* ------------------- OTHER IOCTL ------------------- */
-
-    default:
-      ret = -EOPNOTSUPP;
-    }
+	default:
+		ret = -EOPNOTSUPP;
+	}
 
-  /* Enable interrupts and restore flags. */
-  wv_splx(x);
+	/* Enable interrupts and restore flags. */
+	restore_flags(flags);
 
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
 #endif
-  return ret;
+	return ret;
 }
 
 /*------------------------------------------------------------------*/
@@ -2351,56 +2285,64 @@
  * Get wireless statistics.
  * Called by /proc/net/wireless
  */
-static iw_stats *
-wavelan_get_wireless_stats(device *	dev)
+static iw_stats *wavelan_get_wireless_stats(device * dev)
 {
-  u_long		ioaddr = dev->base_addr;
-  net_local *		lp = (net_local *) dev->priv;
-  mmr_t			m;
-  iw_stats *		wstats;
-  unsigned long		x;
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	mmr_t m;
+	iw_stats *wstats;
+	unsigned long flags;
 
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n",
+	       dev->name);
 #endif
 
-  /* Disable interrupts and save flags. */
-  x = wv_splhi();
+	/* Disable interrupts and save flags. */
+	save_flags(flags);
+	cli();
+	
+	if (lp == (net_local *) NULL)
+	{
+		restore_flags(flags);
+		return (iw_stats *) NULL;
+	}
+	
+	wstats = &lp->wstats;
+
+	/* Get data from the mmc. */
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
 
-  if(lp == (net_local *) NULL)
-    return (iw_stats *) NULL;
-  wstats = &lp->wstats;
-
-  /* Get data from the mmc. */
-  mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-
-  mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
-  mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2);
-  mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4);
-
-  mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
-
-  /* Copy data to wireless stuff. */
-  wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
-  wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
-  wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
-  wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
-  wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) |
-			  ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) |
-			  ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
-  wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
-  wstats->discard.code = 0L;
-  wstats->discard.misc = 0L;
+	mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
+	mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l,
+		 2);
+	mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set,
+		 4);
+
+	mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+
+	/* Copy data to wireless stuff. */
+	wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
+	wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
+	wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
+	wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
+	wstats->qual.updated = (((m. mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) 
+			| ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) 
+			| ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
+	wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+	wstats->discard.code = 0L;
+	wstats->discard.misc = 0L;
 
-  /* Enable interrupts and restore flags. */
-  wv_splx(x);
+	/* Enable interrupts and restore flags. */
+	restore_flags(flags);
 
 #ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n",
+	       dev->name);
 #endif
-  return &lp->wstats;
+	return &lp->wstats;
 }
-#endif	/* WIRELESS_EXT */
+#endif				/* WIRELESS_EXT */
 
 /************************* PACKET RECEPTION *************************/
 /*
@@ -2423,90 +2365,90 @@
  * (called by wv_packet_rcv())
  */
 static inline void
-wv_packet_read(device *		dev,
-	       u_short		buf_off,
-	       int		sksize)
-{
-  net_local *		lp = (net_local *) dev->priv;
-  u_long		ioaddr = dev->base_addr;
-  struct sk_buff *	skb;
+wv_packet_read(device * dev, u16 buf_off, int sksize)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	struct sk_buff *skb;
 
 #ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
-	 dev->name, buf_off, sksize);
+	printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
+	       dev->name, buf_off, sksize);
 #endif
 
-  /* Allocate buffer for the data */
-  if((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL)
-    {
+	/* Allocate buffer for the data */
+	if ((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) {
 #ifdef DEBUG_RX_ERROR
-      printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n",
-	     dev->name, sksize);
+		printk(KERN_INFO
+		       "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n",
+		       dev->name, sksize);
 #endif
-      lp->stats.rx_dropped++;
-      return;
-    }
-
-  skb->dev = dev;
-
-  /* Copy the packet to the buffer. */
-  obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
-  skb->protocol=eth_type_trans(skb, dev);
+		lp->stats.rx_dropped++;
+		return;
+	}
+
+	skb->dev = dev;
+
+	/* Copy the packet to the buffer. */
+	obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
+	skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
-#endif	/* DEBUG_RX_INFO */
+	wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+#endif				/* DEBUG_RX_INFO */
 
-  /* Statistics-gathering and associated stuff.
-   * It seem a bit messy with all the define, but it's really simple... */
+	/* Statistics-gathering and associated stuff.
+	 * It seem a bit messy with all the define, but it's really simple... */
 #if defined(WIRELESS_SPY) || defined(HISTOGRAM)
-  if(
+	if (
 #ifdef WIRELESS_SPY
-     (lp->spy_number > 0) ||
-#endif	/* WIRELESS_SPY */
+		   (lp->spy_number > 0) ||
+#endif				/* WIRELESS_SPY */
 #ifdef HISTOGRAM
-     (lp->his_number > 0) ||
-#endif	/* HISTOGRAM */
-     0)
-    {
-      u_char	stats[3];	/* signal level, noise level, signal quality */
-
-      /* Read signal level, silence level and signal quality bytes. */
-      /* Note: in the PCMCIA hardware, these are part of the frame.  It seems
-       * that for the ISA hardware, it's nowhere to be found in the frame,
-       * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
-       * Any ideas?
-       */
-      mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
-      mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
-      mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
+		   (lp->his_number > 0) ||
+#endif				/* HISTOGRAM */
+		   0) {
+		u8 stats[3];	/* signal level, noise level, signal quality */
+
+		/* Read signal level, silence level and signal quality bytes. */
+		/* Note: in the PCMCIA hardware, these are part of the frame.  It seems
+		 * that for the ISA hardware, it's nowhere to be found in the frame,
+		 * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+		 * Any ideas?
+		 */
+		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
+		mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3);
+		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0);
 
 #ifdef DEBUG_RX_INFO
-      printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
-	     dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F);
+		printk(KERN_DEBUG
+		       "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
+		       dev->name, stats[0] & 0x3F, stats[1] & 0x3F,
+		       stats[2] & 0x0F);
 #endif
 
-      /* Spying stuff */
+		/* Spying stuff */
 #ifdef WIRELESS_SPY
-      wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
-#endif	/* WIRELESS_SPY */
+		wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE,
+			      stats);
+#endif				/* WIRELESS_SPY */
 #ifdef HISTOGRAM
-      wl_his_gather(dev, stats);
-#endif	/* HISTOGRAM */
-    }
-#endif	/* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
-
-  /*
-   * Hand the packet to the network module.
-   */
-  netif_rx(skb);
-
-  /* Keep statistics up to date */
-  lp->stats.rx_packets++;
-  lp->stats.rx_bytes += skb->len;
+		wl_his_gather(dev, stats);
+#endif				/* HISTOGRAM */
+	}
+#endif				/* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
+
+	/*
+	 * Hand the packet to the network module.
+	 */
+	netif_rx(skb);
+
+	/* Keep statistics up to date */
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes += skb->len;
 
 #ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
 #endif
 }
 
@@ -2516,150 +2458,160 @@
  * from the device RAM.
  * Called by the interrupt handler.
  */
-static inline void
-wv_receive(device *	dev)
+static inline void wv_receive(device * dev)
 {
-  u_long	ioaddr = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
-  fd_t		fd;
-  rbd_t		rbd;
-  int		nreaped = 0;
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	fd_t fd;
+	rbd_t rbd;
+	int nreaped = 0;
 
 #ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name);
 #endif
 
-  /* Loop on each received packet. */
-  for(;;)
-    {
-      obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
-
-      /* 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.
-       */
-
-      /* If the current frame is not complete, we have reached the end. */
-      if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
-	break;		/* This is how we exit the loop. */
-
-      nreaped++;
-
-      /* Check whether frame was correctly received. */
-      if((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK)
-	{
-	  /* 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));
+	/* Loop on each received packet. */
+	for (;;) {
+		obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd,
+			   sizeof(fd));
+
+		/* 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.
+		 */
+
+		/* If the current frame is not complete, we have reached the end. */
+		if ((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
+			break;	/* This is how we exit the loop. */
+
+		nreaped++;
+
+		/* Check whether frame was correctly received. */
+		if ((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK) {
+			/* 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));
 
 #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	/* DEBUG_RX_ERROR */
-
-	      /* Read the packet and transmit to Linux */
-	      wv_packet_read(dev, rbd.rbd_bufl,
-			     rbd.rbd_status & RBD_STATUS_ACNT);
-	    }
+				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",
-		   dev->name);
+			else	/* if frame has no data */
+				printk(KERN_INFO
+				       "%s: wv_receive(): frame has no data.\n",
+				       dev->name);
 #endif
-	}
-      else	/* If reception was no successful */
-	{
-	  lp->stats.rx_errors++;
+		} else {	/* If reception was no successful */
+
+			lp->stats.rx_errors++;
 
 #ifdef DEBUG_RX_INFO
-	  printk(KERN_DEBUG "%s: wv_receive(): frame not received successfully (%X).\n",
-		 dev->name, fd.fd_status);
+			printk(KERN_DEBUG
+			       "%s: wv_receive(): frame not received successfully (%X).\n",
+			       dev->name, fd.fd_status);
 #endif
 
 #ifdef DEBUG_RX_ERROR
-	  if((fd.fd_status & FD_STATUS_S6) != 0)
-	    printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name);
+			if ((fd.fd_status & FD_STATUS_S6) != 0)
+				printk(KERN_INFO
+				       "%s: wv_receive(): no EOF flag.\n",
+				       dev->name);
 #endif
 
-	  if((fd.fd_status & FD_STATUS_S7) != 0)
-	    {
-	      lp->stats.rx_length_errors++;
+			if ((fd.fd_status & FD_STATUS_S7) != 0) {
+				lp->stats.rx_length_errors++;
 #ifdef DEBUG_RX_FAIL
-	      printk(KERN_DEBUG "%s: wv_receive(): frame too short.\n",
-		     dev->name);
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): frame too short.\n",
+				       dev->name);
 #endif
-	    }
+			}
 
-	  if((fd.fd_status & FD_STATUS_S8) != 0)
-	    {
-	      lp->stats.rx_over_errors++;
+			if ((fd.fd_status & FD_STATUS_S8) != 0) {
+				lp->stats.rx_over_errors++;
 #ifdef DEBUG_RX_FAIL
-	      printk(KERN_DEBUG "%s: wv_receive(): rx DMA overrun.\n",
-		     dev->name);
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): rx DMA overrun.\n",
+				       dev->name);
 #endif
-	    }
+			}
 
-	  if((fd.fd_status & FD_STATUS_S9) != 0)
-	    {
-	      lp->stats.rx_fifo_errors++;
+			if ((fd.fd_status & FD_STATUS_S9) != 0) {
+				lp->stats.rx_fifo_errors++;
 #ifdef DEBUG_RX_FAIL
-	      printk(KERN_DEBUG "%s: wv_receive(): ran out of resources.\n",
-		     dev->name);
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): ran out of resources.\n",
+				       dev->name);
 #endif
-	    }
+			}
 
-	  if((fd.fd_status & FD_STATUS_S10) != 0)
-	    {
-	      lp->stats.rx_frame_errors++;
+			if ((fd.fd_status & FD_STATUS_S10) != 0) {
+				lp->stats.rx_frame_errors++;
 #ifdef DEBUG_RX_FAIL
-	      printk(KERN_DEBUG "%s: wv_receive(): alignment error.\n",
-		     dev->name);
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): alignment error.\n",
+				       dev->name);
 #endif
-	    }
+			}
 
-	  if((fd.fd_status & FD_STATUS_S11) != 0)
-	    {
-	      lp->stats.rx_crc_errors++;
+			if ((fd.fd_status & FD_STATUS_S11) != 0) {
+				lp->stats.rx_crc_errors++;
 #ifdef DEBUG_RX_FAIL
-	      printk(KERN_DEBUG "%s: wv_receive(): CRC error.\n", dev->name);
-#endif
-	    }
-	}
-
-      fd.fd_status = 0;
-      obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
-		  (unsigned char *) &fd.fd_status, sizeof(fd.fd_status));
-
-      fd.fd_command = FD_COMMAND_EL;
-      obram_write(ioaddr, fdoff(lp->rx_head, fd_command),
-		  (unsigned char *) &fd.fd_command, sizeof(fd.fd_command));
-
-      fd.fd_command = 0;
-      obram_write(ioaddr, fdoff(lp->rx_last, fd_command),
-		  (unsigned char *) &fd.fd_command, sizeof(fd.fd_command));
-
-      lp->rx_last = lp->rx_head;
-      lp->rx_head = fd.fd_link_offset;
-    }	/* for(;;) -> loop on all frames */
+				printk(KERN_DEBUG
+				       "%s: wv_receive(): CRC error.\n",
+				       dev->name);
+#endif
+			}
+		}
+
+		fd.fd_status = 0;
+		obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
+			    (unsigned char *) &fd.fd_status,
+			    sizeof(fd.fd_status));
+
+		fd.fd_command = FD_COMMAND_EL;
+		obram_write(ioaddr, fdoff(lp->rx_head, fd_command),
+			    (unsigned char *) &fd.fd_command,
+			    sizeof(fd.fd_command));
+
+		fd.fd_command = 0;
+		obram_write(ioaddr, fdoff(lp->rx_last, fd_command),
+			    (unsigned char *) &fd.fd_command,
+			    sizeof(fd.fd_command));
+
+		lp->rx_last = lp->rx_head;
+		lp->rx_head = fd.fd_link_offset;
+	}			/* for(;;) -> loop on all frames */
 
 #ifdef DEBUG_RX_INFO
-  if(nreaped > 1)
-    printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", dev->name, nreaped);
+	if (nreaped > 1)
+		printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n",
+		       dev->name, nreaped);
 #endif
 #ifdef DEBUG_RX_TRACE
-  printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name);
 #endif
 }
 
@@ -2689,130 +2641,124 @@
  *
  * (called in wavelan_packet_xmit())
  */
-static inline void
-wv_packet_write(device *	dev,
-		void *	buf,
-		short	length)
-{
-  net_local *		lp = (net_local *) dev->priv;
-  u_long		ioaddr = dev->base_addr;
-  unsigned short	txblock;
-  unsigned short	txpred;
-  unsigned short	tx_addr;
-  unsigned short	nop_addr;
-  unsigned short	tbd_addr;
-  unsigned short	buf_addr;
-  ac_tx_t		tx;
-  ac_nop_t		nop;
-  tbd_t			tbd;
-  int			clen = length;
-  unsigned long		x;
+static inline void wv_packet_write(device * dev, void *buf, short length)
+{
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short txblock;
+	unsigned short txpred;
+	unsigned short tx_addr;
+	unsigned short nop_addr;
+	unsigned short tbd_addr;
+	unsigned short buf_addr;
+	ac_tx_t tx;
+	ac_nop_t nop;
+	tbd_t tbd;
+	int clen = length;
+	unsigned long flags;
 
 #ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
+	printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name,
+	       length);
 #endif
 
-  /* Do we need some padding? */
-  if(clen < ETH_ZLEN)
-    clen = ETH_ZLEN;
-
-  x = wv_splhi();
-
-  /* Calculate addresses of next block and previous block. */
-  txblock = lp->tx_first_free;
-  txpred = txblock - TXBLOCKZ;
-  if(txpred < OFFSET_CU)
-    txpred += NTXBLOCKS * TXBLOCKZ;
-  lp->tx_first_free += TXBLOCKZ;
-  if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-    lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+	/* Do we need some padding? */
+	if (clen < ETH_ZLEN)
+		clen = ETH_ZLEN;
+
+	save_flags(flags);
+	cli();
+	
+	/* Calculate addresses of next block and previous block. */
+	txblock = lp->tx_first_free;
+	txpred = txblock - TXBLOCKZ;
+	if (txpred < OFFSET_CU)
+		txpred += NTXBLOCKS * TXBLOCKZ;
+	lp->tx_first_free += TXBLOCKZ;
+	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+	lp->tx_n_in_use++;
+
+	/* Calculate addresses of the different parts of the block. */
+	tx_addr = txblock;
+	nop_addr = tx_addr + sizeof(tx);
+	tbd_addr = nop_addr + sizeof(nop);
+	buf_addr = tbd_addr + sizeof(tbd);
 
-/*
-if (lp->tx_n_in_use > 0)
-	printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);
-*/
+	/*
+	 * Transmit command
+	 */
+	tx.tx_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
+		    (unsigned char *) &tx.tx_h.ac_status,
+		    sizeof(tx.tx_h.ac_status));
+
+	/*
+	 * NOP command
+	 */
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = nop_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
 
-  lp->tx_n_in_use++;
+	/*
+	 * Transmit buffer descriptor
+	 */
+	tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
+	tbd.tbd_next_bd_offset = I82586NULL;
+	tbd.tbd_bufl = buf_addr;
+	tbd.tbd_bufh = 0;
+	obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd));
 
-  /* Calculate addresses of the different parts of the block. */
-  tx_addr = txblock;
-  nop_addr = tx_addr + sizeof(tx);
-  tbd_addr = nop_addr + sizeof(nop);
-  buf_addr = tbd_addr + sizeof(tbd);
-
-  /*
-   * Transmit command
-   */
-  tx.tx_h.ac_status = 0;
-  obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
-	      (unsigned char *) &tx.tx_h.ac_status,
-	      sizeof(tx.tx_h.ac_status));
-
-  /*
-   * NOP command
-   */
-  nop.nop_h.ac_status = 0;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-	      (unsigned char *) &nop.nop_h.ac_status,
-	      sizeof(nop.nop_h.ac_status));
-  nop.nop_h.ac_link = nop_addr;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-	      (unsigned char *) &nop.nop_h.ac_link,
-	      sizeof(nop.nop_h.ac_link));
-
-  /*
-   * Transmit buffer descriptor
-   */
-  tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen);
-  tbd.tbd_next_bd_offset = I82586NULL;
-  tbd.tbd_bufl = buf_addr;
-  tbd.tbd_bufh = 0;
-  obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd));
-
-  /*
-   * Data
-   */
-  obram_write(ioaddr, buf_addr, buf, length);
-
-  /*
-   * Overwrite the predecessor NOP link
-   * so that it points to this txblock.
-   */
-  nop_addr = txpred + sizeof(tx);
-  nop.nop_h.ac_status = 0;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-	      (unsigned char *)&nop.nop_h.ac_status,
-	      sizeof(nop.nop_h.ac_status));
-  nop.nop_h.ac_link = txblock;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-	      (unsigned char *) &nop.nop_h.ac_link,
-	      sizeof(nop.nop_h.ac_link));
-
-  /* Keep stats up to date. */
-  lp->stats.tx_bytes += length;
-
-  /* If watchdog not already active, activate it... */
-  if(lp->watchdog.prev == (timer_list *) NULL)
-    {
-      /* Set timer to expire in WATCHDOG_JIFFIES. */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
+	/*
+	 * Data
+	 */
+	obram_write(ioaddr, buf_addr, buf, length);
 
-  if(lp->tx_first_in_use == I82586NULL)
-    lp->tx_first_in_use = txblock;
+	/*
+	 * Overwrite the predecessor NOP link
+	 * so that it points to this txblock.
+	 */
+	nop_addr = txpred + sizeof(tx);
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = txblock;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/* Keep stats up to date. */
+	lp->stats.tx_bytes += length;
+
+	/* If watchdog not already active, activate it... */
+	if (lp->watchdog.prev == (timer_list *) NULL) {
+		/* Set timer to expire in WATCHDOG_JIFFIES. */
+		lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+		add_timer(&lp->watchdog);
+	}
 
-  if(lp->tx_n_in_use < NTXBLOCKS - 1)
-    dev->tbusy = 0;
+	if (lp->tx_first_in_use == I82586NULL)
+		lp->tx_first_in_use = txblock;
 
-  wv_splx(x);
+	if (lp->tx_n_in_use < NTXBLOCKS - 1)
+		netif_wake_queue(dev);
 
+	restore_flags(flags);
+	
 #ifdef DEBUG_TX_INFO
-  wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
-#endif	/* DEBUG_TX_INFO */
+	wv_packet_info((u8 *) buf, length, dev->name,
+		       "wv_packet_write");
+#endif				/* DEBUG_TX_INFO */
 
 #ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
 }
 
@@ -2823,59 +2769,41 @@
  * the packet.  We also prevent reentrance.  Then we call the function
  * to send the packet.
  */
-static int
-wavelan_packet_xmit(struct sk_buff *	skb,
-		    device *		dev)
+static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
+	net_local *lp = (net_local *) dev->priv;
 
 #ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-	 (unsigned) skb);
+	printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	       (unsigned) skb);
 #endif
 
-  /* This flag indicate that the hardware can't perform a transmission.
-   * Theoretically, NET3 checks it before sending a packet to the driver,
-   * but in fact it never does that and pools continuously.
-   * As the watchdog will abort overly long transmissions, we are quite safe.
-   */
-  if(dev->tbusy)
-    return 1;
-
-  /*
-   * Block a timer-based transmit from overlapping.
-   * In other words, prevent reentering this routine.
-   */
-  if(test_and_set_bit(0, (void *)&dev->tbusy) != 0)
-#ifdef DEBUG_TX_ERROR
-    printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name);
-#endif
-  else
-    {
-      /* If somebody has asked to reconfigure the controller, 
-       * we can do it now.
-       */
-      if(lp->reconfig_82586)
-	{
-	  wv_82586_config(dev);
-	  if(dev->tbusy)
-	    return 1;
-	}
+	/*
+	 * Block a timer-based transmit from overlapping.
+	 * In other words, prevent reentering this routine.
+	 */
+
+	netif_stop_queue(dev);
 
+	/* If somebody has asked to reconfigure the controller, 
+	 * we can do it now.
+	 */
+	if (lp->reconfig_82586) {
+		wv_82586_config(dev);
+	}
 #ifdef DEBUG_TX_ERROR
-      if(skb->next)
-	printk(KERN_INFO "skb has next\n");
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
 #endif
 
-      wv_packet_write(dev, skb->data, skb->len);
-    }
+	wv_packet_write(dev, skb->data, skb->len);
 
-  dev_kfree_skb(skb);
+	dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*********************** HARDWARE CONFIGURATION ***********************/
@@ -2888,166 +2816,170 @@
  * Routine to initialize the Modem Management Controller.
  * (called by wv_hw_reset())
  */
-static inline int
-wv_mmc_init(device *	dev)
+static inline int wv_mmc_init(device * dev)
 {
-  u_long	ioaddr = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
-  psa_t		psa;
-  mmw_t		m;
-  int		configured;
+	unsigned long ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	psa_t psa;
+	mmw_t m;
+	int configured;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
 #endif
 
-  /* Read the parameter storage area. */
-  psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
+	/* Read the parameter storage area. */
+	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
 
 #ifdef USE_PSA_CONFIG
-  configured = psa.psa_conf_status & 1;
+	configured = psa.psa_conf_status & 1;
 #else
-  configured = 0;
+	configured = 0;
 #endif
 
-  /* Is the PSA is not configured */
-  if(!configured)
-    {
-      /* User will be able to configure NWID later (with iwconfig). */
-      psa.psa_nwid[0] = 0;
-      psa.psa_nwid[1] = 0;
-
-      /* no NWID checking since NWID is not set */
-      psa.psa_nwid_select = 0;
-
-      /* Disable encryption */
-      psa.psa_encryption_select = 0;
-
-      /* Set to standard values:
-       * 0x04 for AT,
-       * 0x01 for MCA,
-       * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
-       */
-      if (psa.psa_comp_number & 1)
-	psa.psa_thr_pre_set = 0x01;
-      else
-	psa.psa_thr_pre_set = 0x04;
-      psa.psa_quality_thr = 0x03;
+	/* Is the PSA is not configured */
+	if (!configured) {
+		/* User will be able to configure NWID later (with iwconfig). */
+		psa.psa_nwid[0] = 0;
+		psa.psa_nwid[1] = 0;
+
+		/* no NWID checking since NWID is not set */
+		psa.psa_nwid_select = 0;
+
+		/* Disable encryption */
+		psa.psa_encryption_select = 0;
+
+		/* Set to standard values:
+		 * 0x04 for AT,
+		 * 0x01 for MCA,
+		 * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
+		 */
+		if (psa.psa_comp_number & 1)
+			psa.psa_thr_pre_set = 0x01;
+		else
+			psa.psa_thr_pre_set = 0x04;
+		psa.psa_quality_thr = 0x03;
 
-      /* It is configured */
-      psa.psa_conf_status |= 1;
+		/* It is configured */
+		psa.psa_conf_status |= 1;
 
 #ifdef USE_PSA_CONFIG
-      /* Write the psa. */
-      psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa,
-		(unsigned char *)psa.psa_nwid, 4);
-      psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
-		(unsigned char *)&psa.psa_thr_pre_set, 1);
-      psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
-		(unsigned char *)&psa.psa_quality_thr, 1);
-      psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa,
-		(unsigned char *)&psa.psa_conf_status, 1);
-      /* update the Wavelan checksum */
-      update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
-    }
-
-  /* Zero the mmc structure. */
-  memset(&m, 0x00, sizeof(m));
-
-  /* Copy PSA info to the mmc. */
-  m.mmw_netw_id_l = psa.psa_nwid[1];
-  m.mmw_netw_id_h = psa.psa_nwid[0];
-  
-  if(psa.psa_nwid_select & 1)
-    m.mmw_loopt_sel = 0x00;
-  else
-    m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
-
-  memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, 
-	 sizeof(m.mmw_encr_key));
-
-  if(psa.psa_encryption_select)
-    m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
-  else
-    m.mmw_encr_enable = 0;
-
-  m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
-  m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
-
-  /*
-   * Set default modem control parameters.
-   * See NCR document 407-0024326 Rev. A.
-   */
-  m.mmw_jabber_enable = 0x01;
-  m.mmw_freeze = 0;
-  m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
-  m.mmw_ifs = 0x20;
-  m.mmw_mod_delay = 0x04;
-  m.mmw_jam_time = 0x38;
-
-  m.mmw_des_io_invert = 0;
-  m.mmw_decay_prm = 0;
-  m.mmw_decay_updat_prm = 0;
-
-  /* Write all info to MMC. */
-  mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m));
-
-  /* The following code starts the modem of the 2.00 frequency
-   * selectable cards at power on.  It's not strictly needed for the
-   * following boots.
-   * The original patch was by Joe Finney for the PCMCIA driver, but
-   * I've cleaned it up a bit and added documentation.
-   * Thanks to Loeke Brederveld from Lucent for the info.
-   */
-
-  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * Does it work for everybody, especially old cards? */
-  /* Note: WFREQSEL verifies that it is able to read a sensible
-   * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID
-   * is 0xA (Xilinx version) or 0xB (Ariadne version).
-   * My test is more crude but does work. */
-  if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
-       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
-    {
-      /* We must download the frequency parameters to the
-       * synthesizers (from the EEPROM - area 1)
-       * Note: as the EEPROM is automatically decremented, we set the end
-       * if the area... */
-      m.mmw_fee_addr = 0x0F;
-      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
-      mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
-		(unsigned char *)&m.mmw_fee_ctrl, 2);
+		/* Write the psa. */
+		psa_write(ioaddr, lp->hacr,
+			  (char *) psa.psa_nwid - (char *) &psa,
+			  (unsigned char *) psa.psa_nwid, 4);
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_thr_pre_set - (char *) &psa,
+			  (unsigned char *) &psa.psa_thr_pre_set, 1);
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_quality_thr - (char *) &psa,
+			  (unsigned char *) &psa.psa_quality_thr, 1);
+		psa_write(ioaddr, lp->hacr,
+			  (char *) &psa.psa_conf_status - (char *) &psa,
+			  (unsigned char *) &psa.psa_conf_status, 1);
+		/* update the Wavelan checksum */
+		update_psa_checksum(dev, ioaddr, lp->hacr);
+#endif
+	}
 
-      /* Wait until the download is finished. */
-      fee_wait(ioaddr, 100, 100);
+	/* Zero the mmc structure. */
+	memset(&m, 0x00, sizeof(m));
 
-#ifdef DEBUG_CONFIG_INFO
-      /* The frequency was in the last word downloaded. */
-      mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m,
-	       (unsigned char *)&m.mmw_fee_data_l, 2);
-
-      /* Print some info for the user. */
-      printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select).  Current frequency = %ld\n",
-	     dev->name,
-	     ((m.mmw_fee_data_h << 4) |
-	      (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
-#endif
-
-      /* We must now download the power adjust value (gain) to
-       * the synthesizers (from the EEPROM - area 7 - DAC). */
-      m.mmw_fee_addr = 0x61;
-      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
-      mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m,
-		(unsigned char *)&m.mmw_fee_ctrl, 2);
+	/* Copy PSA info to the mmc. */
+	m.mmw_netw_id_l = psa.psa_nwid[1];
+	m.mmw_netw_id_h = psa.psa_nwid[0];
+
+	if (psa.psa_nwid_select & 1)
+		m.mmw_loopt_sel = 0x00;
+	else
+		m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
+
+	memcpy(&m.mmw_encr_key, &psa.psa_encryption_key,
+	       sizeof(m.mmw_encr_key));
+
+	if (psa.psa_encryption_select)
+		m.mmw_encr_enable =
+		    MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
+	else
+		m.mmw_encr_enable = 0;
+
+	m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
+	m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
+
+	/*
+	 * Set default modem control parameters.
+	 * See NCR document 407-0024326 Rev. A.
+	 */
+	m.mmw_jabber_enable = 0x01;
+	m.mmw_freeze = 0;
+	m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+	m.mmw_ifs = 0x20;
+	m.mmw_mod_delay = 0x04;
+	m.mmw_jam_time = 0x38;
+
+	m.mmw_des_io_invert = 0;
+	m.mmw_decay_prm = 0;
+	m.mmw_decay_updat_prm = 0;
+
+	/* Write all info to MMC. */
+	mmc_write(ioaddr, 0, (u8 *) & m, sizeof(m));
+
+	/* The following code starts the modem of the 2.00 frequency
+	 * selectable cards at power on.  It's not strictly needed for the
+	 * following boots.
+	 * The original patch was by Joe Finney for the PCMCIA driver, but
+	 * I've cleaned it up a bit and added documentation.
+	 * Thanks to Loeke Brederveld from Lucent for the info.
+	 */
+
+	/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+	 * Does it work for everybody, especially old cards? */
+	/* Note: WFREQSEL verifies that it is able to read a sensible
+	 * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID
+	 * is 0xA (Xilinx version) or 0xB (Ariadne version).
+	 * My test is more crude but does work. */
+	if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
+	      (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
+		/* We must download the frequency parameters to the
+		 * synthesizers (from the EEPROM - area 1)
+		 * Note: as the EEPROM is automatically decremented, we set the end
+		 * if the area... */
+		m.mmw_fee_addr = 0x0F;
+		m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+		mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
+			  (unsigned char *) &m.mmw_fee_ctrl, 2);
 
-      /* Wait until the download is finished. */
-    }	/* if 2.00 card */
+		/* Wait until the download is finished. */
+		fee_wait(ioaddr, 100, 100);
 
+#ifdef DEBUG_CONFIG_INFO
+		/* The frequency was in the last word downloaded. */
+		mmc_read(ioaddr, (char *) &m.mmw_fee_data_l - (char *) &m,
+			 (unsigned char *) &m.mmw_fee_data_l, 2);
+
+		/* Print some info for the user. */
+		printk(KERN_DEBUG
+		       "%s: WaveLAN 2.00 recognised (frequency select).  Current frequency = %ld\n",
+		       dev->name,
+		       ((m.
+			 mmw_fee_data_h << 4) | (m.mmw_fee_data_l >> 4)) *
+		       5 / 2 + 24000L);
+#endif
+
+		/* We must now download the power adjust value (gain) to
+		 * the synthesizers (from the EEPROM - area 7 - DAC). */
+		m.mmw_fee_addr = 0x61;
+		m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+		mmc_write(ioaddr, (char *) &m.mmw_fee_ctrl - (char *) &m,
+			  (unsigned char *) &m.mmw_fee_ctrl, 2);
+
+		/* Wait until the download is finished. */
+	}
+	/* if 2.00 card */
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -3056,81 +2988,79 @@
  * Start the receive unit.
  * (called by wv_hw_reset())
  */
-static inline int
-wv_ru_start(device *	dev)
+static inline int wv_ru_start(device * dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  u_short	scb_cs;
-  fd_t		fd;
-  rbd_t		rbd;
-  u_short	rx;
-  u_short	rx_next;
-  int		i;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cs;
+	fd_t fd;
+	rbd_t rbd;
+	u16 rx;
+	u16 rx_next;
+	int i;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
 #endif
 
-  obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&scb_cs, sizeof(scb_cs));
-  if((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
-    return 0;
-
-  lp->rx_head = OFFSET_RU;
-
-  for(i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next)
-    {
-      rx_next = (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
-
-      fd.fd_status = 0;
-      fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
-      fd.fd_link_offset = rx_next;
-      fd.fd_rbd_offset = rx + sizeof(fd);
-      obram_write(ioaddr, rx, (unsigned char *)&fd, sizeof(fd));
-
-      rbd.rbd_status = 0;
-      rbd.rbd_next_rbd_offset = I82586NULL;
-      rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
-      rbd.rbd_bufh = 0;
-      rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
-      obram_write(ioaddr, rx + sizeof(fd),
-		  (unsigned char *) &rbd, sizeof(rbd));
-
-      lp->rx_last = rx;
-    }
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+		   (unsigned char *) &scb_cs, sizeof(scb_cs));
+	if ((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY)
+		return 0;
+
+	lp->rx_head = OFFSET_RU;
+
+	for (i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) {
+		rx_next =
+		    (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ;
+
+		fd.fd_status = 0;
+		fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0;
+		fd.fd_link_offset = rx_next;
+		fd.fd_rbd_offset = rx + sizeof(fd);
+		obram_write(ioaddr, rx, (unsigned char *) &fd, sizeof(fd));
+
+		rbd.rbd_status = 0;
+		rbd.rbd_next_rbd_offset = I82586NULL;
+		rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd);
+		rbd.rbd_bufh = 0;
+		rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ);
+		obram_write(ioaddr, rx + sizeof(fd),
+			    (unsigned char *) &rbd, sizeof(rbd));
 
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
-	      (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
-
-  scb_cs = SCB_CMD_RUC_GO;
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-	      (unsigned char *) &scb_cs, sizeof(scb_cs));
+		lp->rx_last = rx;
+	}
 
-  set_chan_attn(ioaddr, lp->hacr);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset),
+		    (unsigned char *) &lp->rx_head, sizeof(lp->rx_head));
 
-  for(i = 1000; i > 0; i--)
-    {
-      obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
-		 (unsigned char *) &scb_cs, sizeof(scb_cs));
-      if (scb_cs == 0)
-	break;
+	scb_cs = SCB_CMD_RUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+			   (unsigned char *) &scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
 
-      udelay(10);
-    }
+		udelay(10);
+	}
 
-  if(i <= 0)
-    {
+	if (i <= 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_ru_start(): board not accepting command.\n",
+		       dev->name);
 #endif
-      return -1;
-    }
-
+		return -1;
+	}
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -3150,94 +3080,93 @@
  *
  * (called by wv_hw_reset())
  */
-static inline int
-wv_cu_start(device *	dev)
+static inline int wv_cu_start(device * dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  int		i;
-  u_short	txblock;
-  u_short	first_nop;
-  u_short	scb_cs;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	int i;
+	u16 txblock;
+	u16 first_nop;
+	u16 scb_cs;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name);
 #endif
 
-  lp->tx_first_free = OFFSET_CU;
-  lp->tx_first_in_use = I82586NULL;
+	lp->tx_first_free = OFFSET_CU;
+	lp->tx_first_in_use = I82586NULL;
+
+	for (i = 0, txblock = OFFSET_CU;
+	     i < NTXBLOCKS; i++, txblock += TXBLOCKZ) {
+		ac_tx_t tx;
+		ac_nop_t nop;
+		tbd_t tbd;
+		unsigned short tx_addr;
+		unsigned short nop_addr;
+		unsigned short tbd_addr;
+		unsigned short buf_addr;
+
+		tx_addr = txblock;
+		nop_addr = tx_addr + sizeof(tx);
+		tbd_addr = nop_addr + sizeof(nop);
+		buf_addr = tbd_addr + sizeof(tbd);
+
+		tx.tx_h.ac_status = 0;
+		tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
+		tx.tx_h.ac_link = nop_addr;
+		tx.tx_tbd_offset = tbd_addr;
+		obram_write(ioaddr, tx_addr, (unsigned char *) &tx,
+			    sizeof(tx));
+
+		nop.nop_h.ac_status = 0;
+		nop.nop_h.ac_command = acmd_nop;
+		nop.nop_h.ac_link = nop_addr;
+		obram_write(ioaddr, nop_addr, (unsigned char *) &nop,
+			    sizeof(nop));
+
+		tbd.tbd_status = TBD_STATUS_EOF;
+		tbd.tbd_next_bd_offset = I82586NULL;
+		tbd.tbd_bufl = buf_addr;
+		tbd.tbd_bufh = 0;
+		obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd,
+			    sizeof(tbd));
+	}
 
-  for(i = 0, txblock = OFFSET_CU;
-      i < NTXBLOCKS;
-      i++, txblock += TXBLOCKZ)
-    {
-      ac_tx_t		tx;
-      ac_nop_t		nop;
-      tbd_t		tbd;
-      unsigned short	tx_addr;
-      unsigned short	nop_addr;
-      unsigned short	tbd_addr;
-      unsigned short	buf_addr;
-
-      tx_addr = txblock;
-      nop_addr = tx_addr + sizeof(tx);
-      tbd_addr = nop_addr + sizeof(nop);
-      buf_addr = tbd_addr + sizeof(tbd);
-
-      tx.tx_h.ac_status = 0;
-      tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I;
-      tx.tx_h.ac_link = nop_addr;
-      tx.tx_tbd_offset = tbd_addr;
-      obram_write(ioaddr, tx_addr, (unsigned char *) &tx, sizeof(tx));
-
-      nop.nop_h.ac_status = 0;
-      nop.nop_h.ac_command = acmd_nop;
-      nop.nop_h.ac_link = nop_addr;
-      obram_write(ioaddr, nop_addr, (unsigned char *) &nop, sizeof(nop));
-
-      tbd.tbd_status = TBD_STATUS_EOF;
-      tbd.tbd_next_bd_offset = I82586NULL;
-      tbd.tbd_bufl = buf_addr;
-      tbd.tbd_bufh = 0;
-      obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd));
-    }
-
-  first_nop = OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset),
-	      (unsigned char *) &first_nop, sizeof(first_nop));
-
-  scb_cs = SCB_CMD_CUC_GO;
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-	      (unsigned char *) &scb_cs, sizeof(scb_cs));
-
-  set_chan_attn(ioaddr, lp->hacr);
-
-  for(i = 1000; i > 0; i--)
-    {
-      obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
-		 (unsigned char *) &scb_cs, sizeof(scb_cs));
-      if (scb_cs == 0)
-	break;
+	first_nop =
+	    OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset),
+		    (unsigned char *) &first_nop, sizeof(first_nop));
+
+	scb_cs = SCB_CMD_CUC_GO;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cs, sizeof(scb_cs));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command),
+			   (unsigned char *) &scb_cs, sizeof(scb_cs));
+		if (scb_cs == 0)
+			break;
 
-      udelay(10);
-    }
+		udelay(10);
+	}
 
-  if(i <= 0)
-    {
+	if (i <= 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_cu_start(): board not accepting command.\n",
+		       dev->name);
 #endif
-      return -1;
-    }
-
-  lp->tx_n_in_use = 0;
-  dev->tbusy = 0;
+		return -1;
+	}
 
+	lp->tx_n_in_use = 0;
+	netif_wake_queue(dev);
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -3252,121 +3181,122 @@
  *
  * (called by wv_hw_reset())
  */
-static inline int
-wv_82586_start(device *	dev)
+static inline int wv_82586_start(device * dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  scp_t		scp;		/* system configuration pointer */
-  iscp_t	iscp;		/* intermediate scp */
-  scb_t		scb;		/* system control block */
-  ach_t		cb;		/* Action command header */
-  u_char	zeroes[512];
-  int		i;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	scp_t scp;		/* system configuration pointer */
+	iscp_t iscp;		/* intermediate scp */
+	scb_t scb;		/* system control block */
+	ach_t cb;		/* Action command header */
+	u8 zeroes[512];
+	int i;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name);
 #endif
 
-  /*
-   * Clear the onboard RAM.
-   */
-  memset(&zeroes[0], 0x00, sizeof(zeroes));
-  for(i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
-    obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
-
-  /*
-   * Construct the command unit structures:
-   * scp, iscp, scb, cb.
-   */
-  memset(&scp, 0x00, sizeof(scp));
-  scp.scp_sysbus = SCP_SY_16BBUS;
-  scp.scp_iscpl = OFFSET_ISCP;
-  obram_write(ioaddr, OFFSET_SCP, (unsigned char *)&scp, sizeof(scp));
-
-  memset(&iscp, 0x00, sizeof(iscp));
-  iscp.iscp_busy = 1;
-  iscp.iscp_offset = OFFSET_SCB;
-  obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
-
-  /* Our first command is to reset the i82586. */
-  memset(&scb, 0x00, sizeof(scb));
-  scb.scb_command = SCB_CMD_RESET;
-  scb.scb_cbl_offset = OFFSET_CU;
-  scb.scb_rfa_offset = OFFSET_RU;
-  obram_write(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
-
-  set_chan_attn(ioaddr, lp->hacr);
-
-  /* Wait for command to finish. */
-  for(i = 1000; i > 0; i--)
-    {
-      obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp));
+	/*
+	 * Clear the onboard RAM.
+	 */
+	memset(&zeroes[0], 0x00, sizeof(zeroes));
+	for (i = 0; i < I82586_MEMZ; i += sizeof(zeroes))
+		obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes));
+
+	/*
+	 * Construct the command unit structures:
+	 * scp, iscp, scb, cb.
+	 */
+	memset(&scp, 0x00, sizeof(scp));
+	scp.scp_sysbus = SCP_SY_16BBUS;
+	scp.scp_iscpl = OFFSET_ISCP;
+	obram_write(ioaddr, OFFSET_SCP, (unsigned char *) &scp,
+		    sizeof(scp));
+
+	memset(&iscp, 0x00, sizeof(iscp));
+	iscp.iscp_busy = 1;
+	iscp.iscp_offset = OFFSET_SCB;
+	obram_write(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
+		    sizeof(iscp));
+
+	/* Our first command is to reset the i82586. */
+	memset(&scb, 0x00, sizeof(scb));
+	scb.scb_command = SCB_CMD_RESET;
+	scb.scb_cbl_offset = OFFSET_CU;
+	scb.scb_rfa_offset = OFFSET_RU;
+	obram_write(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+		    sizeof(scb));
+
+	set_chan_attn(ioaddr, lp->hacr);
+
+	/* Wait for command to finish. */
+	for (i = 1000; i > 0; i--) {
+		obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp,
+			   sizeof(iscp));
 
-      if(iscp.iscp_busy == (unsigned short) 0)
-	break;
+		if (iscp.iscp_busy == (unsigned short) 0)
+			break;
 
-      udelay(10);
-    }
+		udelay(10);
+	}
 
-  if(i <= 0)
-    {
+	if (i <= 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wv_82586_start(): iscp_busy timeout.\n",
+		       dev->name);
 #endif
-      return -1;
-    }
+		return -1;
+	}
 
-  /* Check command completion. */
-  for(i = 15; i > 0; i--)
-    {
-      obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb));
+	/* Check command completion. */
+	for (i = 15; i > 0; i--) {
+		obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb,
+			   sizeof(scb));
 
-      if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
-	break;
+		if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
+			break;
 
-      udelay(10);
-    }
+		udelay(10);
+	}
 
-  if (i <= 0)
-    {
+	if (i <= 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
-	     dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
+		printk(KERN_INFO
+		       "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
+		       dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
 #endif
-      return -1;
-    }
+		return -1;
+	}
+
+	wv_ack(dev);
+
+	/* Set the action command header. */
+	memset(&cb, 0x00, sizeof(cb));
+	cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
+	cb.ac_link = OFFSET_CU;
+	obram_write(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
 
-  wv_ack(dev);
+	if (wv_synchronous_cmd(dev, "diag()") == -1)
+		return -1;
 
-  /* Set the action command header. */
-  memset(&cb, 0x00, sizeof(cb));
-  cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose);
-  cb.ac_link = OFFSET_CU;
-  obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
-
-  if(wv_synchronous_cmd(dev, "diag()") == -1)
-    return -1;
-
-  obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
-  if(cb.ac_status & AC_SFLD_FAIL)
-    {
+	obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb));
+	if (cb.ac_status & AC_SFLD_FAIL) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wv_82586_start(): i82586 Self Test failed.\n",
+		       dev->name);
 #endif
-      return -1;
-    }
-
+		return -1;
+	}
 #ifdef DEBUG_I82586_SHOW
-  wv_scb_show(ioaddr);
+	wv_scb_show(ioaddr);
 #endif
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -3383,184 +3313,179 @@
  *
  * (called by wv_hw_reset(), wv_82586_reconfig())
  */
-static void
-wv_82586_config(device *	dev)
+static void wv_82586_config(device * dev)
 {
-  net_local *		lp = (net_local *) dev->priv;
-  u_long		ioaddr = dev->base_addr;
-  unsigned short	txblock;
-  unsigned short	txpred;
-  unsigned short	tx_addr;
-  unsigned short	nop_addr;
-  unsigned short	tbd_addr;
-  unsigned short	cfg_addr;
-  unsigned short	ias_addr;
-  unsigned short	mcs_addr;
-  ac_tx_t		tx;
-  ac_nop_t		nop;
-  ac_cfg_t		cfg;		/* Configure action */
-  ac_ias_t		ias;		/* IA-setup action */
-  ac_mcs_t		mcs;		/* Multicast setup */
-  struct dev_mc_list *	dmi;
-  unsigned long		x;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned short txblock;
+	unsigned short txpred;
+	unsigned short tx_addr;
+	unsigned short nop_addr;
+	unsigned short tbd_addr;
+	unsigned short cfg_addr;
+	unsigned short ias_addr;
+	unsigned short mcs_addr;
+	ac_tx_t tx;
+	ac_nop_t nop;
+	ac_cfg_t cfg;		/* Configure action */
+	ac_ias_t ias;		/* IA-setup action */
+	ac_mcs_t mcs;		/* Multicast setup */
+	struct dev_mc_list *dmi;
+	unsigned long flags;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
 #endif
 
-  x = wv_splhi();
+	save_flags(flags);
+	cli();
+	
+	/* Calculate addresses of next block and previous block. */
+	txblock = lp->tx_first_free;
+	txpred = txblock - TXBLOCKZ;
+	if (txpred < OFFSET_CU)
+		txpred += NTXBLOCKS * TXBLOCKZ;
+	lp->tx_first_free += TXBLOCKZ;
+	if (lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
+		lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
+
+	lp->tx_n_in_use++;
+
+	/* Calculate addresses of the different parts of the block. */
+	tx_addr = txblock;
+	nop_addr = tx_addr + sizeof(tx);
+	tbd_addr = nop_addr + sizeof(nop);
+	cfg_addr = tbd_addr + sizeof(tbd_t);	/* beginning of the buffer */
+	ias_addr = cfg_addr + sizeof(cfg);
+	mcs_addr = ias_addr + sizeof(ias);
+
+	/*
+	 * Transmit command
+	 */
+	tx.tx_h.ac_status = 0xFFFF;	/* Fake completion value */
+	obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
+		    (unsigned char *) &tx.tx_h.ac_status,
+		    sizeof(tx.tx_h.ac_status));
+
+	/*
+	 * NOP command
+	 */
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = nop_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/* Create a configure action. */
+	memset(&cfg, 0x00, sizeof(cfg));
 
-  /* Calculate addresses of next block and previous block. */
-  txblock = lp->tx_first_free;
-  txpred = txblock - TXBLOCKZ;
-  if(txpred < OFFSET_CU)
-    txpred += NTXBLOCKS * TXBLOCKZ;
-  lp->tx_first_free += TXBLOCKZ;
-  if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ)
-    lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ;
-
-  lp->tx_n_in_use++;
-
-  /* Calculate addresses of the different parts of the block. */
-  tx_addr = txblock;
-  nop_addr = tx_addr + sizeof(tx);
-  tbd_addr = nop_addr + sizeof(nop);
-  cfg_addr = tbd_addr + sizeof(tbd_t);	/* beginning of the buffer */
-  ias_addr = cfg_addr + sizeof(cfg);
-  mcs_addr = ias_addr + sizeof(ias);
-
-  /*
-   * Transmit command
-   */
-  tx.tx_h.ac_status = 0xFFFF;	/* Fake completion value */
-  obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status),
-	      (unsigned char *) &tx.tx_h.ac_status,
-	      sizeof(tx.tx_h.ac_status));
-
-  /*
-   * NOP command
-   */
-  nop.nop_h.ac_status = 0;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-	      (unsigned char *) &nop.nop_h.ac_status,
-	      sizeof(nop.nop_h.ac_status));
-  nop.nop_h.ac_link = nop_addr;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-	      (unsigned char *) &nop.nop_h.ac_link,
-	      sizeof(nop.nop_h.ac_link));
-
-  /* Create a configure action. */
-  memset(&cfg, 0x00, sizeof(cfg));
-
-  /*
-   * For Linux we invert AC_CFG_ALOC() so as to conform
-   * to the way that net packets reach us from above.
-   * (See also ac_tx_t.)
-   *
-   * Updated from Wavelan Manual WCIN085B
-   */
-  cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
-  cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
-  cfg.cfg_byte8 = AC_CFG_SAV_BF(1) |
-		  AC_CFG_SRDY(0);
-  cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
-		  AC_CFG_ILPBCK(0) |
-		  AC_CFG_PRELEN(AC_CFG_PLEN_2) |
-		  AC_CFG_ALOC(1) |
-		  AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
-  cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
-		   AC_CFG_ACR(6) |
-		   AC_CFG_LINPRIO(0);
-  cfg.cfg_ifs = 0x20;
-  cfg.cfg_slotl = 0x0C;
-  cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) |
-		   AC_CFG_SLTTMHI(0);
-  cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
-		   AC_CFG_BTSTF(0) |
-		   AC_CFG_CRC16(0) |
-		   AC_CFG_NCRC(0) |
-		   AC_CFG_TNCRS(1) |
-		   AC_CFG_MANCH(0) |
-		   AC_CFG_BCDIS(0) |
-		   AC_CFG_PRM(lp->promiscuous);
-  cfg.cfg_byte15 = AC_CFG_ICDS(0) |
-		   AC_CFG_CDTF(0) |
-		   AC_CFG_ICSS(0) |
-		   AC_CFG_CSTF(0);
+	/*
+	 * For Linux we invert AC_CFG_ALOC() so as to conform
+	 * to the way that net packets reach us from above.
+	 * (See also ac_tx_t.)
+	 *
+	 * Updated from Wavelan Manual WCIN085B
+	 */
+	cfg.cfg_byte_cnt =
+	    AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t));
+	cfg.cfg_fifolim = AC_CFG_FIFOLIM(4);
+	cfg.cfg_byte8 = AC_CFG_SAV_BF(1) | AC_CFG_SRDY(0);
+	cfg.cfg_byte9 = AC_CFG_ELPBCK(0) |
+	    AC_CFG_ILPBCK(0) |
+	    AC_CFG_PRELEN(AC_CFG_PLEN_2) |
+	    AC_CFG_ALOC(1) | AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE);
+	cfg.cfg_byte10 = AC_CFG_BOFMET(1) |
+	    AC_CFG_ACR(6) | AC_CFG_LINPRIO(0);
+	cfg.cfg_ifs = 0x20;
+	cfg.cfg_slotl = 0x0C;
+	cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | AC_CFG_SLTTMHI(0);
+	cfg.cfg_byte14 = AC_CFG_FLGPAD(0) |
+	    AC_CFG_BTSTF(0) |
+	    AC_CFG_CRC16(0) |
+	    AC_CFG_NCRC(0) |
+	    AC_CFG_TNCRS(1) |
+	    AC_CFG_MANCH(0) |
+	    AC_CFG_BCDIS(0) | AC_CFG_PRM(lp->promiscuous);
+	cfg.cfg_byte15 = AC_CFG_ICDS(0) |
+	    AC_CFG_CDTF(0) | AC_CFG_ICSS(0) | AC_CFG_CSTF(0);
 /*
   cfg.cfg_min_frm_len = AC_CFG_MNFRM(64);
 */
-  cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
+	cfg.cfg_min_frm_len = AC_CFG_MNFRM(8);
 
-  cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure);
-  cfg.cfg_h.ac_link = ias_addr;
-  obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg));
-
-  /* Set up the MAC address */
-  memset(&ias, 0x00, sizeof(ias));
-  ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
-  ias.ias_h.ac_link = mcs_addr;
-  memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr));
-  obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias));
-
-  /* Initialize adapter's Ethernet multicast addresses */
-  memset(&mcs, 0x00, sizeof(mcs));
-  mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
-  mcs.mcs_h.ac_link = nop_addr;
-  mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
-  obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs));
-
-  /* Any address to set? */
-  if(lp->mc_count)
-    {
-      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
-	outsw(PIOP1(ioaddr), (u_short *) dmi->dmi_addr,
-	      WAVELAN_ADDR_SIZE >> 1);
+	cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure);
+	cfg.cfg_h.ac_link = ias_addr;
+	obram_write(ioaddr, cfg_addr, (unsigned char *) &cfg, sizeof(cfg));
+
+	/* Set up the MAC address */
+	memset(&ias, 0x00, sizeof(ias));
+	ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup);
+	ias.ias_h.ac_link = mcs_addr;
+	memcpy(&ias.ias_addr[0], (unsigned char *) &dev->dev_addr[0],
+	       sizeof(ias.ias_addr));
+	obram_write(ioaddr, ias_addr, (unsigned char *) &ias, sizeof(ias));
+
+	/* Initialize adapter's Ethernet multicast addresses */
+	memset(&mcs, 0x00, sizeof(mcs));
+	mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup);
+	mcs.mcs_h.ac_link = nop_addr;
+	mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count;
+	obram_write(ioaddr, mcs_addr, (unsigned char *) &mcs, sizeof(mcs));
+
+	/* Any address to set? */
+	if (lp->mc_count) {
+		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+			outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr,
+			      WAVELAN_ADDR_SIZE >> 1);
 
 #ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n",
-	     dev->name, lp->mc_count);
-      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
-	printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
-	       dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
-#endif
-    }
-
-  /*
-   * Overwrite the predecessor NOP link
-   * so that it points to the configure action.
-   */
-  nop_addr = txpred + sizeof(tx);
-  nop.nop_h.ac_status = 0;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
-	      (unsigned char *)&nop.nop_h.ac_status,
-	      sizeof(nop.nop_h.ac_status));
-  nop.nop_h.ac_link = cfg_addr;
-  obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
-	      (unsigned char *) &nop.nop_h.ac_link,
-	      sizeof(nop.nop_h.ac_link));
-
-  /* If watchdog not already active, activate it... */
-  if(lp->watchdog.prev == (timer_list *) NULL)
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  lp->reconfig_82586 = 0;
+		printk(KERN_DEBUG
+		       "%s: wv_82586_config(): set %d multicast addresses:\n",
+		       dev->name, lp->mc_count);
+		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+			printk(KERN_DEBUG
+			       " %02x:%02x:%02x:%02x:%02x:%02x\n",
+			       dmi->dmi_addr[0], dmi->dmi_addr[1],
+			       dmi->dmi_addr[2], dmi->dmi_addr[3],
+			       dmi->dmi_addr[4], dmi->dmi_addr[5]);
+#endif
+	}
+
+	/*
+	 * Overwrite the predecessor NOP link
+	 * so that it points to the configure action.
+	 */
+	nop_addr = txpred + sizeof(tx);
+	nop.nop_h.ac_status = 0;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status),
+		    (unsigned char *) &nop.nop_h.ac_status,
+		    sizeof(nop.nop_h.ac_status));
+	nop.nop_h.ac_link = cfg_addr;
+	obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link),
+		    (unsigned char *) &nop.nop_h.ac_link,
+		    sizeof(nop.nop_h.ac_link));
+
+	/* If watchdog not already active, activate it... */
+	if (lp->watchdog.prev == (timer_list *) NULL) {
+		/* set timer to expire in WATCHDOG_JIFFIES */
+		lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+		add_timer(&lp->watchdog);
+	}
 
-  if(lp->tx_first_in_use == I82586NULL)
-    lp->tx_first_in_use = txblock;
+	lp->reconfig_82586 = 0;
 
-  if(lp->tx_n_in_use < NTXBLOCKS - 1)
-    dev->tbusy = 0;
+	if (lp->tx_first_in_use == I82586NULL)
+		lp->tx_first_in_use = txblock;
 
-  wv_splx(x);
+	if (lp->tx_n_in_use < NTXBLOCKS - 1)
+		netif_wake_queue(dev);
 
+	restore_flags(flags);
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
 #endif
 }
 
@@ -3569,28 +3494,29 @@
  * This routine, called by wavelan_close(), gracefully stops the 
  * WaveLAN controller (i82586).
  */
-static inline void
-wv_82586_stop(device *	dev)
+static inline void wv_82586_stop(device * dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
-  u_long	ioaddr = dev->base_addr;
-  u_short	scb_cmd;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	u16 scb_cmd;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name);
 #endif
 
-  /* Suspend both command unit and receive unit. */
-  scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS);
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-	      (unsigned char *)&scb_cmd, sizeof(scb_cmd));
-  set_chan_attn(ioaddr, lp->hacr);
+	/* Suspend both command unit and receive unit. */
+	scb_cmd =
+	    (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC &
+					       SCB_CMD_RUC_SUS);
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &scb_cmd, sizeof(scb_cmd));
+	set_chan_attn(ioaddr, lp->hacr);
 
-  /* No more interrupts */
-  wv_ints_off(dev);
+	/* No more interrupts */
+	wv_ints_off(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name);
 #endif
 }
 
@@ -3604,49 +3530,47 @@
  *	4. Start the LAN controller's command unit
  *	5. Start the LAN controller's receive unit
  */
-static int
-wv_hw_reset(device *	dev)
+static int wv_hw_reset(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
-  u_long	ioaddr = dev->base_addr;
+	net_local *lp = (net_local *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name,
-	 (unsigned int)dev);
+	printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name,
+	       (unsigned int) dev);
 #endif
 
-  /* If watchdog was activated, kill it! */
-  if(lp->watchdog.prev != (timer_list *) NULL)
-    del_timer(&lp->watchdog);
+	/* If watchdog was activated, kill it! */
+	if (lp->watchdog.prev != (timer_list *) NULL)
+		del_timer(&lp->watchdog);
 
-  /* Increase the number of resets done. */
-  lp->nresets++;
+	/* Increase the number of resets done. */
+	lp->nresets++;
 
-  wv_hacr_reset(ioaddr);
-  lp->hacr = HACR_DEFAULT;
+	wv_hacr_reset(ioaddr);
+	lp->hacr = HACR_DEFAULT;
 
-  if((wv_mmc_init(dev) < 0) ||
-     (wv_82586_start(dev) < 0))
-    return -1;
+	if ((wv_mmc_init(dev) < 0) || (wv_82586_start(dev) < 0))
+		return -1;
 
-  /* Enable the card to send interrupts. */
-  wv_ints_on(dev);
+	/* Enable the card to send interrupts. */
+	wv_ints_on(dev);
 
-  /* Start card functions */
-  if(wv_cu_start(dev) < 0)
-    return -1;
+	/* Start card functions */
+	if (wv_cu_start(dev) < 0)
+		return -1;
 
-  /* Setup the controller and parameters */
-  wv_82586_config(dev);
+	/* Setup the controller and parameters */
+	wv_82586_config(dev);
 
-  /* Finish configuration with the receive unit */
-  if(wv_ru_start(dev) < 0)
-    return -1;
+	/* Finish configuration with the receive unit */
+	if (wv_ru_start(dev) < 0)
+		return -1;
 
 #ifdef DEBUG_CONFIG_TRACE
-  printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -3655,40 +3579,39 @@
  * As a side effect, this reads the MAC address.
  * (called in wavelan_probe() and init_module())
  */
-static int
-wv_check_ioaddr(u_long		ioaddr,
-		u_char *	mac)
-{
-  int		i;		/* Loop counter */
-
-  /* Check if the base address if available. */
-  if(check_region(ioaddr, sizeof(ha_t)))
-    return  EADDRINUSE;		/* ioaddr already used */
-
-  /* Reset host interface */
-  wv_hacr_reset(ioaddr);
-
-  /* Read the MAC address from the parameter storage area. */
-  psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
-	   mac, 6);
-
-  /*
-   * Check the first three octets of the address for the manufacturer's code.
-   * Note: if this can't find your WaveLAN card, you've got a
-   * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
-   * how to configure your card.
-   */
-  for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
-    if((mac[0] == MAC_ADDRESSES[i][0]) &&
-       (mac[1] == MAC_ADDRESSES[i][1]) &&
-       (mac[2] == MAC_ADDRESSES[i][2]))
-      return 0;
+static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac)
+{
+	int i;			/* Loop counter */
+
+	/* Check if the base address if available. */
+	if (check_region(ioaddr, sizeof(ha_t)))
+		return EADDRINUSE;	/* ioaddr already used */
+
+	/* Reset host interface */
+	wv_hacr_reset(ioaddr);
+
+	/* Read the MAC address from the parameter storage area. */
+	psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr),
+		 mac, 6);
+
+	/*
+	 * Check the first three octets of the address for the manufacturer's code.
+	 * Note: if this can't find your WaveLAN card, you've got a
+	 * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
+	 * how to configure your card.
+	 */
+	for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+		if ((mac[0] == MAC_ADDRESSES[i][0]) &&
+		    (mac[1] == MAC_ADDRESSES[i][1]) &&
+		    (mac[2] == MAC_ADDRESSES[i][2]))
+			return 0;
 
 #ifdef DEBUG_CONFIG_INFO
-  printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
-	 ioaddr, mac[0], mac[1], mac[2]);
+	printk(KERN_WARNING
+	       "WaveLAN (0x%3X): your MAC address might be %02X:%02X:%02X.\n",
+	       ioaddr, mac[0], mac[1], mac[2]);
 #endif
-    return ENODEV;
+	return ENODEV;
 }
 
 /************************ INTERRUPT HANDLING ************************/
@@ -3697,133 +3620,121 @@
  * This function is the interrupt handler for the WaveLAN card. This
  * routine will be called whenever: 
  */
-static void
-wavelan_interrupt(int			irq,
-		  void *		dev_id,
-		  struct pt_regs *	regs)
-{
-  device *	dev;
-  u_long	ioaddr;
-  net_local *	lp;
-  u_short	hasr;
-  u_short	status;
-  u_short	ack_cmd;
+static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	device *dev;
+	unsigned long ioaddr;
+	net_local *lp;
+	u16 hasr;
+	u16 status;
+	u16 ack_cmd;
 
-  dev = dev_id;
+	dev = dev_id;
 
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
 #endif
 
-  lp = (net_local *) dev->priv;
-  ioaddr = dev->base_addr;
+	lp = (net_local *) dev->priv;
+	ioaddr = dev->base_addr;
 
-  /* Prevent reentrance. What should we do here? */
-#ifdef DEBUG_INTERRUPT_ERROR
-  if(dev->interrupt)
-    printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n",
-	   dev->name);
-#endif
-  dev->interrupt = 1;
-
-  if((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR)
-    {
-      u_char	dce_status;
-
-      /*
-       * Interrupt from the modem management controller.
-       * This will clear it -- ignored for now.
-       */
-      mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status));
+	/* Prevent reentrance. What should we do here? */
+
+	if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
+		u8 dce_status;
+
+		/*
+		 * Interrupt from the modem management controller.
+		 * This will clear it -- ignored for now.
+		 */
+		mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status,
+			 sizeof(dce_status));
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
-	     dev->name, dce_status);
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
+		       dev->name, dce_status);
 #endif
-    }
+	}
 
-  if((hasr & HASR_82586_INTR) == 0)
-    {
-      dev->interrupt = 0;
+	if ((hasr & HASR_82586_INTR) == 0) {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
+		       dev->name);
 #endif
-      return;
-    }
+		return;
+	}
 
-  /* Read interrupt data. */
-  obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
-	     (unsigned char *) &status, sizeof(status));
-
-  /*
-   * Acknowledge the interrupt(s).
-   */
-  ack_cmd = status & SCB_ST_INT;
-  obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
-	      (unsigned char *) &ack_cmd, sizeof(ack_cmd));
-  set_chan_attn(ioaddr, lp->hacr);
+	/* Read interrupt data. */
+	obram_read(ioaddr, scboff(OFFSET_SCB, scb_status),
+		   (unsigned char *) &status, sizeof(status));
+
+	/*
+	 * Acknowledge the interrupt(s).
+	 */
+	ack_cmd = status & SCB_ST_INT;
+	obram_write(ioaddr, scboff(OFFSET_SCB, scb_command),
+		    (unsigned char *) &ack_cmd, sizeof(ack_cmd));
+	set_chan_attn(ioaddr, lp->hacr);
 
 #ifdef DEBUG_INTERRUPT_INFO
-  printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n",
-	 dev->name, status);
+	printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n",
+	       dev->name, status);
 #endif
 
-  /* Command completed. */
-  if((status & SCB_ST_CX) == SCB_ST_CX)
-    {
+	/* Command completed. */
+	if ((status & SCB_ST_CX) == SCB_ST_CX) {
 #ifdef DEBUG_INTERRUPT_INFO
-      printk(KERN_DEBUG "%s: wavelan_interrupt(): command completed.\n",
-	     dev->name);
+		printk(KERN_DEBUG
+		       "%s: wavelan_interrupt(): command completed.\n",
+		       dev->name);
 #endif
-      wv_complete(dev, ioaddr, lp);
+		wv_complete(dev, ioaddr, lp);
 
-      /* If watchdog was activated, kill it ! */
-      if(lp->watchdog.prev != (timer_list *) NULL)
-	del_timer(&lp->watchdog);
-      if(lp->tx_n_in_use > 0)
-	{
-	  /* set timer to expire in WATCHDOG_JIFFIES */
-	  lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-	  add_timer(&lp->watchdog);
-	}
-    }
-
-  /* Frame received. */
-  if((status & SCB_ST_FR) == SCB_ST_FR)
-    {
+		/* If watchdog was activated, kill it ! */
+		if (lp->watchdog.prev != (timer_list *) NULL)
+			del_timer(&lp->watchdog);
+		if (lp->tx_n_in_use > 0) {
+			/* set timer to expire in WATCHDOG_JIFFIES */
+			lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+			add_timer(&lp->watchdog);
+		}
+	}
+
+	/* Frame received. */
+	if ((status & SCB_ST_FR) == SCB_ST_FR) {
 #ifdef DEBUG_INTERRUPT_INFO
-      printk(KERN_DEBUG "%s: wavelan_interrupt(): received packet.\n",
-	     dev->name);
+		printk(KERN_DEBUG
+		       "%s: wavelan_interrupt(): received packet.\n",
+		       dev->name);
 #endif
-      wv_receive(dev);
-    }
+		wv_receive(dev);
+	}
 
-  /* Check the state of the command unit. */
-  if(((status & SCB_ST_CNA) == SCB_ST_CNA) ||
-     (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start))
-    {
+	/* Check the state of the command unit. */
+	if (((status & SCB_ST_CNA) == SCB_ST_CNA) ||
+	    (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && test_bit(LINK_STATE_START, &dev->state))) {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): CU inactive -- restarting\n",
+		       dev->name);
 #endif
-      wv_hw_reset(dev);
-    }
+		wv_hw_reset(dev);
+	}
 
-  /* Check the state of the command unit. */
-  if(((status & SCB_ST_RNR) == SCB_ST_RNR) ||
-     (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start))
-    {
+	/* Check the state of the command unit. */
+	if (((status & SCB_ST_RNR) == SCB_ST_RNR) ||
+	    (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && test_bit(LINK_STATE_START, &dev->state))) {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): RU not ready -- restarting\n",
+		       dev->name);
 #endif
-      wv_hw_reset(dev);
-    }
-
-  dev->interrupt = 0;
+		wv_hw_reset(dev);
+	}
 
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
 #endif
 }
 
@@ -3838,83 +3749,81 @@
  * way because the overhead of add_timer() and del_timer() is nothing
  * and because it avoids calling the watchdog, saving some CPU.
  */
-static void
-wavelan_watchdog(u_long		a)
+static void wavelan_watchdog(unsigned long a)
 {
-  device *		dev;
-  net_local *		lp;
-  u_long		ioaddr;
-  unsigned long		x;
-  unsigned int		nreaped;
-
-  dev = (device *) a;
-  ioaddr = dev->base_addr;
-  lp = (net_local *) dev->priv;
+	device *dev;
+	net_local *lp;
+	unsigned long ioaddr;
+	unsigned long flags;
+	unsigned int nreaped;
+
+	dev = (device *) a;
+	ioaddr = dev->base_addr;
+	lp = (net_local *) dev->priv;
 
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
+	printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
 #endif
 
 #ifdef DEBUG_INTERRUPT_ERROR
-  printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
-	 dev->name);
+	printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
+	       dev->name);
 #endif
 
-  x = wv_splhi();
-
-  dev = (device *) a;
-  ioaddr = dev->base_addr;
-  lp = (net_local *) dev->priv;
-
-  if(lp->tx_n_in_use <= 0)
-    {
-      wv_splx(x);
-      return;
-    }
+	save_flags(flags);
+	cli();
+	
+	dev = (device *) a;
+	ioaddr = dev->base_addr;
+	lp = (net_local *) dev->priv;
+
+	if (lp->tx_n_in_use <= 0) {
+		restore_flags(flags);
+		return;
+	}
 
-  nreaped = wv_complete(dev, ioaddr, lp);
+	nreaped = wv_complete(dev, ioaddr, lp);
 
 #ifdef DEBUG_INTERRUPT_INFO
-  printk(KERN_DEBUG "%s: wavelan_watchdog(): %d reaped, %d remain.\n",
-	 dev->name, nreaped, lp->tx_n_in_use);
+	printk(KERN_DEBUG
+	       "%s: wavelan_watchdog(): %d reaped, %d remain.\n",
+	       dev->name, nreaped, lp->tx_n_in_use);
 #endif
 
 #ifdef DEBUG_PSA_SHOW
-  {
-    psa_t		psa;
-    psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
-    wv_psa_show(&psa);
-  }
+	{
+		psa_t psa;
+		psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+		wv_psa_show(&psa);
+	}
 #endif
 #ifdef DEBUG_MMC_SHOW
-  wv_mmc_show(dev);
+	wv_mmc_show(dev);
 #endif
 #ifdef DEBUG_I82586_SHOW
-  wv_cu_show(dev);
+	wv_cu_show(dev);
 #endif
 
-  /* If no buffer has been freed */
-  if(nreaped == 0)
-    {
+	/* If no buffer has been freed */
+	if (nreaped == 0) {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "%s: wavelan_watchdog(): cleanup failed, trying reset\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_watchdog(): cleanup failed, trying reset\n",
+		       dev->name);
 #endif
-      wv_hw_reset(dev);
-    }
-  else
-    /* Reset watchdog for next transmission. */
-    if(lp->tx_n_in_use > 0)
-      {
-	/* set timer to expire in WATCHDOG_JIFFIES */
-	lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-	add_timer(&lp->watchdog);
-      }
-
-  wv_splx(x);
+		wv_hw_reset(dev);
+	} else
+		/* Reset watchdog for next transmission. */
+	if (lp->tx_n_in_use > 0) {
+		/* set timer to expire in WATCHDOG_JIFFIES */
+		lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
+		add_timer(&lp->watchdog);
+	}
 
+	restore_flags(flags);
+	
 #ifdef DEBUG_INTERRUPT_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
 #endif
 }
 
@@ -3930,56 +3839,55 @@
  * Configure and start up the WaveLAN PCMCIA adaptor.
  * Called by NET3 when it "opens" the device.
  */
-static int
-wavelan_open(device *	dev)
+static int wavelan_open(device * dev)
 {
-  u_long	x;
+	unsigned long flags;
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
-	 (unsigned int) dev);
+	printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
+	       (unsigned int) dev);
 #endif
 
-  /* Check irq */
-  if(dev->irq == 0)
-    {
+	/* Check irq */
+	if (dev->irq == 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
+		printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n",
+		       dev->name);
 #endif
-      return -ENXIO;
-    }
+		return -ENXIO;
+	}
 
-  if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
-    {
+	if (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0) 
+	{
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
+		printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n",
+		       dev->name);
 #endif
-      return -EAGAIN;
-    }
+		return -EAGAIN;
+	}
 
-  x = wv_splhi();
-  if(wv_hw_reset(dev) != -1)
-    {
-      dev->interrupt = 0;
-      dev->start = 1;
-    }
-  else
-    {
-      free_irq(dev->irq, dev);
+	save_flags(flags);
+	cli();
+	
+	if (wv_hw_reset(dev) != -1) {
+		netif_start_queue(dev);
+	} else {
+		free_irq(dev->irq, dev);
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n",
-	     dev->name);
+		printk(KERN_INFO
+		       "%s: wavelan_open(): impossible to start the card\n",
+		       dev->name);
 #endif
-      return -EAGAIN;
-    }
-  wv_splx(x);
-
-  MOD_INC_USE_COUNT;
+		return -EAGAIN;
+	}
+	restore_flags(flags);
+	
+	MOD_INC_USE_COUNT;
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -3987,40 +3895,34 @@
  * Shut down the WaveLAN ISA card.
  * Called by NET3 when it "closes" the device.
  */
-static int
-wavelan_close(device *	dev)
+static int wavelan_close(device * dev)
 {
-  net_local *	lp = (net_local *)dev->priv;
+	net_local *lp = (net_local *) dev->priv;
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
-	 (unsigned int) dev);
+	printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
+	       (unsigned int) dev);
 #endif
 
-  /* Don't do the job twice. */
-  if(dev->start == 0)
-    return 0;
-
-  dev->tbusy = 1;
-  dev->start = 0;
+	netif_stop_queue(dev);
 
-  /* If watchdog was activated, kill it! */
-  if(lp->watchdog.prev != (timer_list *) NULL)
-    del_timer(&lp->watchdog);
+	/* If watchdog was activated, kill it! */
+	if (lp->watchdog.prev != (timer_list *) NULL)
+		del_timer(&lp->watchdog);
 
-  /*
-   * Flush the Tx and disable Rx.
-   */
-  wv_82586_stop(dev);
+	/*
+	 * Flush the Tx and disable Rx.
+	 */
+	wv_82586_stop(dev);
 
-  free_irq(dev->irq, dev);
+	free_irq(dev->irq, dev);
 
-  MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -4029,113 +3931,111 @@
  * device structure
  * (called by wavelan_probe() and via init_module()).
  */
-static int __init 
-wavelan_config(device *	dev)
+static int __init wavelan_config(device * dev)
 {
-  u_long	ioaddr = dev->base_addr;
-  u_char	irq_mask;
-  int		irq;
-  net_local *	lp;
+	unsigned long ioaddr = dev->base_addr;
+	u8 irq_mask;
+	int irq;
+	net_local *lp;
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n", dev->name,
-	 (unsigned int)dev, ioaddr);
+	printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n",
+	       dev->name, (unsigned int) dev, ioaddr);
 #endif
 
-  /* Check IRQ argument on command line. */
-  if(dev->irq != 0)
-    {
-      irq_mask = wv_irq_to_psa(dev->irq);
+	/* Check IRQ argument on command line. */
+	if (dev->irq != 0) {
+		irq_mask = wv_irq_to_psa(dev->irq);
 
-      if(irq_mask == 0)
-	{
+		if (irq_mask == 0) {
 #ifdef DEBUG_CONFIG_ERROR
-	  printk(KERN_WARNING "%s: wavelan_config(): invalid IRQ %d ignored.\n",
-		 dev->name, dev->irq);
+			printk(KERN_WARNING
+			       "%s: wavelan_config(): invalid IRQ %d ignored.\n",
+			       dev->name, dev->irq);
 #endif
-	  dev->irq = 0;
-	}
-      else
-	{
+			dev->irq = 0;
+		} else {
 #ifdef DEBUG_CONFIG_INFO
-	  printk(KERN_DEBUG "%s: wavelan_config(): changing IRQ to %d\n",
-		 dev->name, dev->irq);
-#endif
-	  psa_write(ioaddr, HACR_DEFAULT,
-		    psaoff(0, psa_int_req_no), &irq_mask, 1);
-	  /* update the Wavelan checksum */
-	  update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
-	  wv_hacr_reset(ioaddr);
-	}
-    }
-
-  psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), &irq_mask, 1);
-  if((irq = wv_psa_to_irq(irq_mask)) == -1)
-    {
+			printk(KERN_DEBUG
+			       "%s: wavelan_config(): changing IRQ to %d\n",
+			       dev->name, dev->irq);
+#endif
+			psa_write(ioaddr, HACR_DEFAULT,
+				  psaoff(0, psa_int_req_no), &irq_mask, 1);
+			/* update the Wavelan checksum */
+			update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
+			wv_hacr_reset(ioaddr);
+		}
+	}
+
+	psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no),
+		 &irq_mask, 1);
+	if ((irq = wv_psa_to_irq(irq_mask)) == -1) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_INFO "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
-	     dev->name, irq_mask);
+		printk(KERN_INFO
+		       "%s: wavelan_config(): could not wavelan_map_irq(%d).\n",
+		       dev->name, irq_mask);
 #endif
-      return EAGAIN;
-    }
+		return EAGAIN;
+	}
+
+	dev->irq = irq;
 
-  dev->irq = irq;
+	request_region(ioaddr, sizeof(ha_t), "wavelan");
 
-  request_region(ioaddr, sizeof(ha_t), "wavelan");
-
-  dev->mem_start = 0x0000;
-  dev->mem_end = 0x0000;
-  dev->if_port = 0;
-
-  /* Initialize device structures */
-  dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
-  if(dev->priv == NULL)
-    return -ENOMEM;
-  memset(dev->priv, 0x00, sizeof(net_local));
-  lp = (net_local *)dev->priv;
-
-  /* Back link to the device structure. */
-  lp->dev = dev;
-  /* Add the device at the beginning of the linked list. */
-  lp->next = wavelan_list;
-  wavelan_list = lp;
-
-  lp->hacr = HACR_DEFAULT;
-
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
-  lp->promiscuous = 0;
-  lp->mc_count = 0;
-
-  /*
-   * Fill in the fields of the device structure
-   * with generic Ethernet values.
-   */
-  ether_setup(dev);
-
-  dev->open = wavelan_open;
-  dev->stop = wavelan_close;
-  dev->hard_start_xmit = wavelan_packet_xmit;
-  dev->get_stats = wavelan_get_stats;
-  dev->set_multicast_list = &wavelan_set_multicast_list;
+	dev->mem_start = 0x0000;
+	dev->mem_end = 0x0000;
+	dev->if_port = 0;
+
+	/* Initialize device structures */
+	dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0x00, sizeof(net_local));
+	lp = (net_local *) dev->priv;
+
+	/* Back link to the device structure. */
+	lp->dev = dev;
+	/* Add the device at the beginning of the linked list. */
+	lp->next = wavelan_list;
+	wavelan_list = lp;
+
+	lp->hacr = HACR_DEFAULT;
+
+	lp->watchdog.function = wavelan_watchdog;
+	lp->watchdog.data = (unsigned long) dev;
+	lp->promiscuous = 0;
+	lp->mc_count = 0;
+
+	/*
+	 * Fill in the fields of the device structure
+	 * with generic Ethernet values.
+	 */
+	ether_setup(dev);
+
+	dev->open = wavelan_open;
+	dev->stop = wavelan_close;
+	dev->hard_start_xmit = wavelan_packet_xmit;
+	dev->get_stats = wavelan_get_stats;
+	dev->set_multicast_list = &wavelan_set_multicast_list;
 #ifdef SET_MAC_ADDRESS
-  dev->set_mac_address = &wavelan_set_mac_address;
-#endif	/* SET_MAC_ADDRESS */
+	dev->set_mac_address = &wavelan_set_mac_address;
+#endif				/* SET_MAC_ADDRESS */
 
-#ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
-  dev->do_ioctl = wavelan_ioctl;
-  dev->get_wireless_stats = wavelan_get_wireless_stats;
+#ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
+	dev->do_ioctl = wavelan_ioctl;
+	dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
-  dev->mtu = WAVELAN_MTU;
+	dev->mtu = WAVELAN_MTU;
 
-  /* Display nice information. */
-  wv_init_info(dev);
+	/* Display nice information. */
+	wv_init_info(dev);
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
+	printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name);
 #endif
-  return 0;
+	return 0;
 }
 
 /*------------------------------------------------------------------*/
@@ -4146,90 +4046,88 @@
  * We follow the example in drivers/net/ne.c.
  * (called in "Space.c")
  */
-int __init 
-wavelan_probe(device *	dev)
+int __init wavelan_probe(device * dev)
 {
-  short		base_addr;
-  mac_addr	mac;		/* MAC address (check existence of WaveLAN) */
-  int		i;
-  int		r;
+	short base_addr;
+	mac_addr mac;		/* MAC address (check existence of WaveLAN) */
+	int i;
+	int r;
 
 #ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
-	 dev->name, (unsigned int)dev, (unsigned int)dev->base_addr);
+	printk(KERN_DEBUG
+	       "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n",
+	       dev->name, (unsigned int) dev,
+	       (unsigned int) dev->base_addr);
 #endif
 
 #ifdef	STRUCT_CHECK
-  if (wv_struct_check() != (char *) NULL)
-    {
-      printk(KERN_WARNING "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
-	     dev->name, wv_struct_check());
-      return ENODEV;
-    }
-#endif	/* STRUCT_CHECK */
-
-  /* Check the value of the command line parameter for base address. */
-  base_addr = dev->base_addr;
-
-  /* Don't probe at all. */
-  if(base_addr < 0)
-    {
+	if (wv_struct_check() != (char *) NULL) {
+		printk(KERN_WARNING
+		       "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
+		       dev->name, wv_struct_check());
+		return ENODEV;
+	}
+#endif				/* STRUCT_CHECK */
+
+	/* Check the value of the command line parameter for base address. */
+	base_addr = dev->base_addr;
+
+	/* Don't probe at all. */
+	if (base_addr < 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n",
-	     dev->name);
+		printk(KERN_WARNING
+		       "%s: wavelan_probe(): invalid base address\n",
+		       dev->name);
 #endif
-      return ENXIO;
-    }
-
-  /* Check a single specified location. */
-  if(base_addr > 0x100)
-    {
-      /* Check if there is something at this base address */
-      if((r = wv_check_ioaddr(base_addr, mac)) == 0)
-	{
-	  memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-	  r = wavelan_config(dev);
+		return ENXIO;
 	}
 
+	/* Check a single specified location. */
+	if (base_addr > 0x100) {
+		/* Check if there is something at this base address */
+		if ((r = wv_check_ioaddr(base_addr, mac)) == 0) {
+			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
+			r = wavelan_config(dev);
+		}
 #ifdef DEBUG_CONFIG_INFO
-      if(r != 0)
-	printk(KERN_DEBUG "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n",
-	       dev->name, base_addr);
+		if (r != 0)
+			printk(KERN_DEBUG
+			       "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n",
+			       dev->name, base_addr);
 #endif
 
 #ifdef DEBUG_CALLBACK_TRACE
-      printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
+		printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
 #endif
-      return r;
-    }
+		return r;
+	}
 
-  /* Scan all possible addresses of the WaveLAN hardware. */
-  for(i = 0; i < NELS(iobase); i++)
-    {
-      /* Check whether there is something at this base address. */
-      if(wv_check_ioaddr(iobase[i], mac) == 0)
-	{
-	  dev->base_addr = iobase[i];		/* Copy base address. */
-	  memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-	  if(wavelan_config(dev) == 0)
-	    {
+	/* Scan all possible addresses of the WaveLAN hardware. */
+	for (i = 0; i < NELS(iobase); i++) {
+		/* Check whether there is something at this base address. */
+		if (wv_check_ioaddr(iobase[i], mac) == 0) {
+			dev->base_addr = iobase[i];	/* Copy base address. */
+			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
+			if (wavelan_config(dev) == 0) {
 #ifdef DEBUG_CALLBACK_TRACE
-	      printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
-#endif
-	      return 0;
-	    }
+				printk(KERN_DEBUG
+				       "%s: <-wavelan_probe()\n",
+				       dev->name);
+#endif
+				return 0;
+			}
+		}
 	}
-    }
 
-  /* We may have touched base_addr.  Another driver may not like it. */
-  dev->base_addr = base_addr;
+	/* We may have touched base_addr.  Another driver may not like it. */
+	dev->base_addr = base_addr;
 
 #ifdef DEBUG_CONFIG_INFO
-  printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
-	 dev->name);
+	printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n",
+	       dev->name);
 #endif
 
-  return ENODEV;
+	return ENODEV;
 }
 
 /****************************** MODULE ******************************/
@@ -4243,120 +4141,115 @@
  * Insertion of the module
  * I'm now quite proud of the multi-device support.
  */
-int
-init_module(void)
+int init_module(void)
 {
-  mac_addr	mac;		/* MAC address (check WaveLAN existence) */
-  int		ret = -EIO;	/* Return error if no cards found */
-  int		i;
+	mac_addr mac;		/* MAC address (check WaveLAN existence) */
+	int ret = -EIO;		/* Return error if no cards found */
+	int i;
 
 #ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "-> init_module()\n");
+	printk(KERN_DEBUG "-> init_module()\n");
 #endif
 
-  /* If probing is asked */
-  if(io[0] == 0)
-    {
+	/* If probing is asked */
+	if (io[0] == 0) {
 #ifdef DEBUG_CONFIG_ERROR
-      printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
-      printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
+		printk(KERN_WARNING
+		       "WaveLAN init_module(): doing device probing (bad !)\n");
+		printk(KERN_WARNING
+		       "Specify base addresses while loading module to correct the problem\n");
 #endif
 
-      /* Copy the basic set of address to be probed. */
-      for(i = 0; i < NELS(iobase); i++)
-	io[i] = iobase[i];
-    }
-
-
-  /* Loop on all possible base addresses. */
-  i = -1;
-  while((io[++i] != 0) && (i < NELS(io)))
-    {
-      /* Check if there is something at this base address. */
-      if(wv_check_ioaddr(io[i], mac) == 0)
-	{
-	  device *	dev;
+		/* Copy the basic set of address to be probed. */
+		for (i = 0; i < NELS(iobase); i++)
+			io[i] = iobase[i];
+	}
 
-	  /* Create device and set basic arguments. */
-	  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-	  if(dev==NULL)
-	  {
-	  	ret = -ENOMEM;
-	  	break;
-	  }
-	  memset(dev, 0x00, sizeof(struct net_device));
-	  dev->name = name[i];
-	  dev->base_addr = io[i];
-	  dev->irq = irq[i];
-	  dev->init = &wavelan_config;
-	  memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
-
-	  /* Try to create the device. */
-	  if(register_netdev(dev) != 0)
-	    {
-	      /* Deallocate everything. */
-	      /* Note: if dev->priv is mallocated, there is no way to fail. */
-	      kfree_s(dev, sizeof(struct net_device));
-	    }
-	  else
-	    {
-              /* If at least one device OK, we do not fail */
-              ret = 0;
-	    }
-	}	/* if there is something at the address */
-    }		/* Loop on all addresses. */
+
+	/* Loop on all possible base addresses. */
+	i = -1;
+	while ((io[++i] != 0) && (i < NELS(io))) {
+		/* Check if there is something at this base address. */
+		if (wv_check_ioaddr(io[i], mac) == 0) {
+			device *dev;
+
+			/* Create device and set basic arguments. */
+			dev =
+			    kmalloc(sizeof(struct net_device), GFP_KERNEL);
+			if (dev == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+			memset(dev, 0x00, sizeof(struct net_device));
+			dev->name = name[i];
+			dev->base_addr = io[i];
+			dev->irq = irq[i];
+			dev->init = &wavelan_config;
+			memcpy(dev->dev_addr, mac, 6);	/* Copy MAC address. */
+
+			/* Try to create the device. */
+			if (register_netdev(dev) != 0) {
+				/* Deallocate everything. */
+				/* Note: if dev->priv is mallocated, there is no way to fail. */
+				kfree_s(dev, sizeof(struct net_device));
+			} else {
+				/* If at least one device OK, we do not fail */
+				ret = 0;
+			}
+		}		/* if there is something at the address */
+	}			/* Loop on all addresses. */
 
 #ifdef DEBUG_CONFIG_ERROR
-  if(wavelan_list == (net_local *) NULL)
-    printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
+	if (wavelan_list == (net_local *) NULL)
+		printk(KERN_WARNING
+		       "WaveLAN init_module(): no device found\n");
 #endif
 
 #ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "<- init_module()\n");
+	printk(KERN_DEBUG "<- init_module()\n");
 #endif
-  return ret;
+	return ret;
 }
 
 /*------------------------------------------------------------------*/
 /*
  * Removal of the module
  */
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 #ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "-> cleanup_module()\n");
+	printk(KERN_DEBUG "-> cleanup_module()\n");
 #endif
 
-  /* Loop on all devices and release them. */
-  while(wavelan_list != (net_local *) NULL)
-    {
-      device *	dev = wavelan_list->dev;
+	/* Loop on all devices and release them. */
+	while (wavelan_list != (net_local *) NULL) {
+		device *dev = wavelan_list->dev;
 
 #ifdef DEBUG_CONFIG_INFO
-      printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n",
-	     dev->name, (unsigned int) dev);
+		printk(KERN_DEBUG
+		       "%s: cleanup_module(): removing device at 0x%x\n",
+		       dev->name, (unsigned int) dev);
 #endif
 
-      /* Release the ioport region. */
-      release_region(dev->base_addr, sizeof(ha_t));
+		/* Release the ioport region. */
+		release_region(dev->base_addr, sizeof(ha_t));
 
-      /* Definitely remove the device. */
-      unregister_netdev(dev);
+		/* Definitely remove the device. */
+		unregister_netdev(dev);
 
-      /* Unlink the device. */
-      wavelan_list = wavelan_list->next;
+		/* Unlink the device. */
+		wavelan_list = wavelan_list->next;
 
-      /* Free pieces. */
-      kfree_s(dev->priv, sizeof(struct net_local));
-      kfree_s(dev, sizeof(struct net_device));
-    }
+		/* Free pieces. */
+		kfree_s(dev->priv, sizeof(struct net_local));
+		kfree_s(dev, sizeof(struct net_device));
+	}
 
 #ifdef DEBUG_MODULE_TRACE
-  printk(KERN_DEBUG "<- cleanup_module()\n");
+	printk(KERN_DEBUG "<- cleanup_module()\n");
 #endif
 }
-#endif	/* MODULE */
+#endif				/* MODULE */
 
 /*
  * This software may only be used and distributed
@@ -4379,7 +4272,7 @@
  *
  * Thanks go also to:
  *	James Ashton (jaa101@syseng.anu.edu.au),
- *	Alan Cox (iialan@iiit.swan.ac.uk),
+ *	Alan Cox (alan@redhat.com),
  *	Allan Creighton (allanc@cs.usyd.edu.au),
  *	Matthew Geier (matthew@cs.usyd.edu.au),
  *	Remo di Giovanni (remo@cs.usyd.edu.au),
diff -u --recursive --new-file v2.3.44/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v2.3.44/linux/drivers/net/znet.c	Wed Aug 18 11:36:43 1999
+++ linux/drivers/net/znet.c	Sun Feb 13 10:25:33 2000
@@ -119,10 +119,13 @@
 #define CMD0_STAT2 (2 << 5)
 #define CMD0_STAT3 (3 << 5)
 
+#define TX_TIMEOUT	10
+
 #define net_local znet_private
 struct znet_private {
 	int rx_dma, tx_dma;
 	struct net_device_stats stats;
+	spinlock_t lock;
 	/* The starting, current, and end pointers for the packet buffers. */
 	ushort *rx_start, *rx_cur, *rx_end;
 	ushort *tx_start, *tx_cur, *tx_end;
@@ -190,6 +193,7 @@
 static void set_multicast_list(struct net_device *dev);
 static void hardware_init(struct net_device *dev);
 static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
+static void znet_tx_timeout (struct net_device *dev);
 
 #ifdef notdef
 static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, };
@@ -245,6 +249,7 @@
 	dev->priv = (void *) &zn;
 	zn.rx_dma = netinfo->dma1;
 	zn.tx_dma = netinfo->dma2;
+	zn.lock = SPIN_LOCK_UNLOCKED;
 
 	/* These should never fail.  You can't add devices to a sealed box! */
 	if (request_irq(dev->irq, &znet_interrupt, 0, "ZNet", dev)
@@ -275,6 +280,8 @@
 	dev->stop = &znet_close;
 	dev->get_stats	= net_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
+	dev->tx_timeout = znet_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
 
 	/* Fill in the 'dev' with ethernet-generic values. */
 	ether_setup(dev);
@@ -306,41 +313,47 @@
 		printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
 			   dev->name);
 
-	dev->tbusy = 0;
-	dev->interrupt = 0;
 	hardware_init(dev);
-	dev->start = 1;
+	netif_start_queue (dev);
 
 	return 0;
 }
 
+
+static void znet_tx_timeout (struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	ushort event, tx_status, rx_offset, state;
+
+	outb (CMD0_STAT0, ioaddr);
+	event = inb (ioaddr);
+	outb (CMD0_STAT1, ioaddr);
+	tx_status = inw (ioaddr);
+	outb (CMD0_STAT2, ioaddr);
+	rx_offset = inw (ioaddr);
+	outb (CMD0_STAT3, ioaddr);
+	state = inb (ioaddr);
+	printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
+	 " resetting.\n", dev->name, event, tx_status, rx_offset, state);
+	if (tx_status == 0x0400)
+		printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
+			dev->name);
+	outb (CMD0_RESET, ioaddr);
+	hardware_init (dev);
+	netif_start_queue (dev);
+}
+
 static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
 
 	if (znet_debug > 4)
-		printk(KERN_DEBUG "%s: ZNet_send_packet(%ld).\n", dev->name, dev->tbusy);
-
-	/* Transmitter timeout, likely just recovery after suspending the machine. */
-	if (dev->tbusy) {
-		ushort event, tx_status, rx_offset, state;
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 10)
-			return 1;
-		outb(CMD0_STAT0, ioaddr); event = inb(ioaddr);
-		outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr);
-		outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr);
-		outb(CMD0_STAT3, ioaddr); state = inb(ioaddr);
-		printk(KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
-			   " resetting.\n", dev->name, event, tx_status, rx_offset, state);
-		if (tx_status == 0x0400)
-		  printk(KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
-				 dev->name);
-		outb(CMD0_RESET, ioaddr);
-		hardware_init(dev);
-	}
+		printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
 
+	netif_stop_queue (dev);
+	
 	/* Check that the part hasn't reset itself, probably from suspend. */
 	outb(CMD0_STAT0, ioaddr);
 	if (inw(ioaddr) == 0x0010
@@ -348,11 +361,7 @@
 		&& inw(ioaddr) == 0x0010)
 	  hardware_init(dev);
 
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-	else {
+	if (1) {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = (void *)skb->data;
 		ushort *tx_link = zn.tx_cur - 1;
@@ -385,13 +394,18 @@
 			zn.tx_cur += rnd_len;
 		}
 		*zn.tx_cur++ = 0;
-		cli(); {
+
+		spin_lock_irqsave(&lp->lock, flags);
+		{
 			*tx_link = CMD0_TRANSMIT + CMD0_CHNL_1;
 			/* Is this always safe to do? */
 			outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr);
-		} sti();
+		}
+		spin_unlock_irqrestore (&lp->lock, flags);
 
 		dev->trans_start = jiffies;
+		netif_start_queue (dev);
+
 		if (znet_debug > 4)
 		  printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
 	}
@@ -403,6 +417,7 @@
 static void	znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
+	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr;
 	int boguscnt = 20;
 
@@ -411,7 +426,8 @@
 		return;
 	}
 
-	dev->interrupt = 1;
+	spin_lock (&lp->lock);
+	
 	ioaddr = dev->base_addr;
 
 	outb(CMD0_STAT0, ioaddr);
@@ -432,7 +448,6 @@
 			break;
 
 		if ((status & 0x0F) == 4) {	/* Transmit done. */
-			struct net_local *lp = (struct net_local *)dev->priv;
 			int tx_status;
 			outb(CMD0_STAT1, ioaddr);
 			tx_status = inw(ioaddr);
@@ -449,8 +464,7 @@
 				if ((tx_status | 0x0760) != 0x0760)
 				  lp->stats.tx_errors++;
 			}
-			dev->tbusy = 0;
-			mark_bh(NET_BH);	/* Inform upper layers. */
+			netif_wake_queue (dev);
 		}
 
 		if ((status & 0x40)
@@ -461,7 +475,8 @@
 		outb(CMD0_ACK,ioaddr);
 	} while (boguscnt--);
 
-	dev->interrupt = 0;
+	spin_unlock (&lp->lock);
+	
 	return;
 }
 
@@ -594,8 +609,7 @@
 	unsigned long flags;
 	int ioaddr = dev->base_addr;
 
-	dev->tbusy = 1;
-	dev->start = 0;
+	netif_stop_queue (dev);
 
 	outb(CMD0_RESET, ioaddr);			/* CMD0_RESET */
 
@@ -728,7 +742,7 @@
 	update_stop_hit(ioaddr, 8192);
 	if (znet_debug > 1)  printk("enabling Rx.\n");
 	outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr);
-	dev->tbusy = 0;
+	netif_start_queue (dev);
 }
 
 static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.3.44/linux/drivers/scsi/eata.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/eata.c	Sun Feb 13 18:20:21 2000
@@ -910,7 +910,7 @@
    if (info.sign != EATA_SIGNATURE) return FALSE;
 
    if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
-      printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+      printk("%s: config structure size (%d bytes) too short, detaching.\n",
              name, DEV2H(info.data_len));
       return FALSE;
       }
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.3.44/linux/drivers/scsi/hosts.h	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/hosts.h	Sun Feb 13 19:05:39 2000
@@ -504,6 +504,15 @@
  * tackle the character devices first, as there aren't any locking implications
  * in the block device layer.   The block devices will require more work.
  */
+#ifndef CONFIG_SD_EXTRA_DEVS
+#define CONFIG_SD_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_ST_EXTRA_DEVS
+#define CONFIG_ST_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_SR_EXTRA_DEVS
+#define CONFIG_SR_EXTRA_DEVS 2
+#endif
 #define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
 #define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS
 #define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/mac_esp.c linux/drivers/scsi/mac_esp.c
--- v2.3.44/linux/drivers/scsi/mac_esp.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/mac_esp.c	Sun Feb 13 11:21:42 2000
@@ -417,7 +417,9 @@
 			esp->irq = IRQ_MAC_SCSI;
 
 			request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp);
+#if 0	/* conflicts with IOP ADB */
 			request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp);
+#endif
 
 			if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
 				esp->cfreq = 16500000;
@@ -429,8 +431,9 @@
 		} else { /* chipnum == 1 */
 
 			esp->irq = IRQ_MAC_SCSIDRQ;
-
+#if 0	/* conflicts with IOP ADB */
 			request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp);
+#endif
 
 			esp->cfreq = 25000000;
 
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/mac_scsi.c linux/drivers/scsi/mac_scsi.c
--- v2.3.44/linux/drivers/scsi/mac_scsi.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/mac_scsi.c	Sun Feb 13 11:21:42 2000
@@ -78,7 +78,6 @@
 #define NDEBUG (NDEBUG_ABORT)
 #endif
 
-#define USE_WRAPPER
 #define RESET_BOOT
 #define DRIVER_SETUP
 
@@ -90,30 +89,9 @@
 #undef DRIVER_SETUP
 #endif
 
-/* 
- * Need to define this to make SCSI work on RBV machines; leave undefined
- * to enable interrupts a bit more on other machines 
- * Changes method of SCSI interrupt disable from software mask to VIA IER!
- * (don't know if that's essential)
- *
- * 990502 (jmt) - not needed (and won't work) on new irq architecture
- */
-/* #define RBV_HACK */
-
-#ifdef RBV_HACK
-#define	ENABLE_IRQ()	mac_turnon_irq( IRQ_MAC_SCSI ); 
-#define	DISABLE_IRQ()	mac_turnoff_irq( IRQ_MAC_SCSI );
-#else
 #define	ENABLE_IRQ()	mac_enable_irq( IRQ_MAC_SCSI ); 
 #define	DISABLE_IRQ()	mac_disable_irq( IRQ_MAC_SCSI );
-#endif
-
-#define mac_turnon_irq(x) mac_enable_irq(x)
-#define mac_turnoff_irq(x) mac_disable_irq(x)
 
-extern void via_scsi_clear(void);
-
-static void scsi_mac_intr(int irq, void *dummy, struct pt_regs *fp);
 #ifdef RESET_BOOT
 static void mac_scsi_reset_boot(struct Scsi_Host *instance);
 #endif
@@ -253,7 +231,7 @@
     if (macintosh_config->scsi_type != MAC_SCSI_OLD)
 	 return( 0 );
 
-    tpnt->proc_name = "Mac 5380 SCSI";
+    tpnt->proc_name = "mac5380";
 
     /* setup variables */
     tpnt->can_queue =
@@ -306,11 +284,7 @@
         ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
 
 	if (instance->irq != IRQ_NONE)
-#ifdef USE_WRAPPER
-	    if (request_irq(instance->irq, scsi_mac_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) {
-#else
-	    if (request_irq(instance->irq, macscsi_intr, IRQ_FLG_SLOW, "MacSCSI-5380", NULL)) {
-#endif
+	    if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) {
 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
@@ -337,7 +311,7 @@
 int macscsi_release (struct Scsi_Host *shpnt)
 {
 	if (shpnt->irq != IRQ_NONE)
-		free_irq (shpnt->irq, NULL);
+		free_irq (shpnt->irq, NCR5380_intr);
 
 	return 0;
 }
@@ -362,7 +336,7 @@
 	printk( "Macintosh SCSI: resetting the SCSI bus..." );
 
 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-       	mac_turnoff_irq( IRQ_MAC_SCSI );
+       	mac_disable_irq(IRQ_MAC_SCSI);
 
 	/* get in phase */
 	NCR5380_write( TARGET_COMMAND_REG,
@@ -380,7 +354,7 @@
 		barrier();
 
 	/* switch on SCSI IRQ again */
-       	mac_turnon_irq( IRQ_MAC_SCSI );
+       	mac_enable_irq(IRQ_MAC_SCSI);
 
 	printk( " done\n" );
 }
@@ -399,49 +373,6 @@
 	restore_flags(flags);
 }
 
-#ifdef USE_WRAPPER
-/*
- * SCSI interrupt wrapper - just to make sure it's the proper irq, and 
- * that we leave the handler in a clean state
- */
-
-static void scsi_mac_intr (int irq, void *dev_id, struct pt_regs *fp)
-{
-#ifndef RBV_HACK
-	unsigned long flags;
-#endif
-
-#ifdef RBV_HACK
-	mac_turnoff_irq( IRQ_MAC_SCSI );
-#else
-	mac_disable_irq( IRQ_MAC_SCSI );
-#endif
-
-	if ( irq == IRQ_MAC_SCSI ) {
-#ifndef RBV_HACK
-		save_flags(flags);
-		restore_irq(fp);
-#endif
-		NCR5380_intr (irq, dev_id, fp);
-#ifndef RBV_HACK
-		restore_flags(flags);
-#endif
-	}
-
-	/* To be sure the int is not masked */
-#ifdef RBV_HACK
-	mac_turnon_irq( IRQ_MAC_SCSI );
-#else
-	mac_enable_irq( IRQ_MAC_SCSI );
-#endif
-
-#if 1	/* ??? 0 worked */
-	/* Clear the IRQ */
-	via_scsi_clear();
-#endif
-}
-#endif
-
 /*
  * pseudo-DMA transfer functions, copied and modified from Russel King's
  * ARM 5380 driver (cumana_1)
@@ -720,11 +651,7 @@
 			printk("SCSI poll\n");
 			save_flags(flags);
 			cli();
-#ifdef USE_WRAPPER
-			scsi_mac_intr(IRQ_MAC_SCSI, instance, NULL);
-#else
-			macscsi_intr(IRQ_MAC_SCSI, instance, NULL);
-#endif
+			NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
 			restore_flags(flags);
 		}
 #if 0
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c
--- v2.3.44/linux/drivers/scsi/mvme16x.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/mvme16x.c	Sun Feb 13 11:21:42 2000
@@ -40,7 +40,7 @@
     if (called)
 	return 0;
 
-    tpnt->proc_name = "MVME16x"
+    tpnt->proc_name = "MVME16x";
 
     options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
 
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c
--- v2.3.44/linux/drivers/scsi/qla1280.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/qla1280.c	Sun Feb 13 10:30:38 2000
@@ -182,6 +182,7 @@
     -   Initial Beta Release.  
 *****************************************************************************/
 
+
 #ifdef MODULE
 #include <linux/module.h>
 #endif
@@ -2789,7 +2790,7 @@
 
         DEBUG(sprintf(debug_buff,"qla1280_setup_chip:  loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);)
         DEBUG(qla1280_print(debug_buff));
-        printk("qla1280_setup_chip:  loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address);
+        DEBUG(printk("qla1280_setup_chip:  loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address));
         BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1));
         mb[0] = MBC_LOAD_RAM; 
         /* mb[0] = MBC_LOAD_RAM_A64; */
@@ -2799,7 +2800,7 @@
         mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff;
         mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff);
         mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff;
-        printk("qla1280_setup_chip: op=%d  0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]);
+        DEBUG(printk("qla1280_setup_chip: op=%d  0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]));
         if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0,
             &mb[0]))  )
         {
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.44/linux/drivers/scsi/qlogicisp.c	Thu Feb 10 17:11:13 2000
+++ linux/drivers/scsi/qlogicisp.c	Sun Feb 13 10:14:58 2000
@@ -811,6 +811,7 @@
 		ds = cmd->dataseg;
 
 		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg);
+		Cmnd->use_sg = sg_count;
 
 		cmd->segment_cnt = cpu_to_le16(sg_count);
 
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/sun3_NCR5380.c linux/drivers/scsi/sun3_NCR5380.c
--- v2.3.44/linux/drivers/scsi/sun3_NCR5380.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/sun3_NCR5380.c	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,3012 @@
+/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by 
+   Sam Creasey. */ 
+/* 
+ * NCR 5380 generic driver routines.  These should make it *trivial*
+ * 	to implement 5380 SCSI drivers under Linux with a non-trantor
+ *	architecture.
+ *
+ *	Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing 
+ *	(Unix and Linux consulting and custom programming)
+ * 	drew@colorado.edu
+ *	+1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ *  - Some of the debug statements were incorrect (undefined variables and the
+ *    like). I fixed that.
+ *
+ *  - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ *    possible DMA transfer size should also happen for REAL_DMA. I added this
+ *    in the #if statement.
+ *
+ *  - When using real DMA, information_transfer() should return in a DATAOUT
+ *    phase after starting the DMA. It has nothing more to do.
+ *
+ *  - The interrupt service routine should run main after end of DMA, too (not
+ *    only after RESELECTION interrupts). Additionally, it should _not_ test
+ *    for more interrupts after running main, since a DMA process may have
+ *    been started and interrupts are turned on now. The new int could happen
+ *    inside the execution of NCR5380_intr(), leading to recursive
+ *    calls.
+ *
+ *  - I've added a function merge_contiguous_buffers() that tries to
+ *    merge scatter-gather buffers that are located at contiguous
+ *    physical addresses and can be processed with the same DMA setup.
+ *    Since most scatter-gather operations work on a page (4K) of
+ *    4 buffers (1K), in more than 90% of all cases three interrupts and
+ *    DMA setup actions are saved.
+ *
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ *    and USLEEP, because these were messing up readability and will never be
+ *    needed for Atari SCSI.
+ * 
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ *   stuff), and 'main' is executed in a bottom half if awoken by an
+ *   interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ *   constructs. In my eyes, this made the source rather unreadable, so I
+ *   finally replaced that by the *_PRINTK() macros.
+ *
+ */
+
+/*
+ * Further development / testing that should be done : 
+ * 1.  Test linked command handling code after Eric is ready with 
+ *     the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+    if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \
+	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+    if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip.  This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued 
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that 
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what 
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver.  To use it on a different platform, 
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use 
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for 
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing.  This means that an 
+ * unlimited number of commands may be queued, letting 
+ * more commands propagate from the higher driver levels giving higher 
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
+ * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem, 
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system.  So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.  
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the 
+ * NCR5380_print_options command, which should be called from the 
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 : 
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
+ * piece of hardware that requires you to sit in a loop polling for 
+ * the REQ signal as long as you are connected.  Some devices are 
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * while doing long seek operations.
+ * 
+ * The workaround for this is to keep track of devices that have
+ * disconnected.  If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like 
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ * 
+ * Some tweaking of N and M needs to be done.  An algorithm based 
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these 
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function.  It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the 
+ * issue queue and calling NCR5380_select() if a nexus 
+ * is not established. 
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work.  If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr()  which will in turn call NCR5380_reselect
+ * to reestablish a nexus.  This will run main if necessary.
+ *
+ * On command termination, the done function will be called as 
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command 
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips.  To use it, you write an architecture specific functions 
+ * and macros and include this file in your driver.
+ *
+ * These macros control options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *	for commands that return with a CHECK CONDITION status. 
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ * 
+ * NCR5380_read(register)  - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register 
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions : 
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *	that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *	available as NCR5380_i386_dma_write_setup,
+ *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define 
+ *  
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie 
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID.  If the 
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used.  Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define	SETUP_HOSTDATA(in)				\
+    struct NCR5380_hostdata *hostdata =			\
+	(struct NCR5380_hostdata *)(in)->hostdata
+#define	HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define	NEXT(cmd)	((Scsi_Cmnd *)((cmd)->host_scribble))
+#define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define	HOSTNO		instance->host_no
+#define	H_NO(cmd)	(cmd)->host->host_no
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
+#if (MAX_TAGS % 32) != 0
+#error "MAX_TAGS must be a multiple of 32!"
+#endif
+
+typedef struct {
+    char	allocated[MAX_TAGS/8];
+    int		nr_allocated;
+    int		queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void __init init_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+    
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	    /* At the beginning, assume the maximum queue size we could
+	     * support (MAX_TAGS). This value will be decreased if the target
+	     * returns QUEUE_FULL status.
+	     */
+	    ta->queue_size = MAX_TAGS;
+	}
+    }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */ 
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+	return( 1 );
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
+	return( 0 );
+    if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
+	TagAlloc[cmd->target][cmd->lun].queue_size ) {
+	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+		    H_NO(cmd), cmd->target, cmd->lun );
+	return( 1 );
+    }
+    return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    /* If we or the target don't support tagged queuing, allocate the LUN for
+     * an untagged command.
+     */
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+	cmd->tag = TAG_NONE;
+	hostdata->busy[cmd->target] |= (1 << cmd->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+		    "command\n", H_NO(cmd), cmd->target, cmd->lun );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+
+	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
+	set_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated++;
+	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+		    "(now %d tags in use)\n",
+		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+		    ta->nr_allocated );
+    }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    if (cmd->tag == TAG_NONE) {
+	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+		    H_NO(cmd), cmd->target, cmd->lun );
+    }
+    else if (cmd->tag >= MAX_TAGS) {
+	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+		H_NO(cmd), cmd->tag );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	clear_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated--;
+	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+    }
+}
+
+
+static void free_all_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	}
+    }
+}
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ *    transfer. This is possible if the scatter buffers lie on
+ *    physical contiguous addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ *    The command to work on. The first scatter buffer's data are
+ *    assumed to be already transfered into ptr/this_residual.
+ */
+
+static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+{
+    unsigned long endaddr;
+#if (NDEBUG & NDEBUG_MERGING)
+    unsigned long oldlen = cmd->SCp.this_residual;
+    int		  cnt = 1;
+#endif
+
+    for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+	 cmd->SCp.buffers_residual &&
+	 virt_to_phys(cmd->SCp.buffer[1].address) == endaddr; ) {
+	
+	MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+		   cmd->SCp.buffer[1].address, endaddr);
+#if (NDEBUG & NDEBUG_MERGING)
+	++cnt;
+#endif
+	++cmd->SCp.buffer;
+	--cmd->SCp.buffers_residual;
+	cmd->SCp.this_residual += cmd->SCp.buffer->length;
+	endaddr += cmd->SCp.buffer->length;
+    }
+#if (NDEBUG & NDEBUG_MERGING)
+    if (oldlen != cmd->SCp.this_residual)
+	MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+		   cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the 
+ *	start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+    /* 
+     * Initialize the Scsi Pointer field so that all of the commands in the 
+     * various queues are valid.
+     */
+
+    if (cmd->use_sg) {
+	cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+	cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
+	cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	/* ++roman: Try to merge some scatter-buffers if they are at
+	 * contiguous physical addresses.
+	 */
+	merge_contiguous_buffers( cmd );
+    } else {
+	cmd->SCp.buffer = NULL;
+	cmd->SCp.buffers_residual = 0;
+	cmd->SCp.ptr = (char *) cmd->request_buffer;
+	cmd->SCp.this_residual = cmd->request_bufflen;
+    }
+    
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#if 1
+static struct {
+    unsigned char mask;
+    const char * name;} 
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
+    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
+    { SR_SEL, "SEL" }, {0, NULL}}, 
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
+    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
+    {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
+    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
+    "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+    {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
+    {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+    unsigned char status, data, basr, mr, icr, i;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+    status = NCR5380_read(STATUS_REG);
+    mr = NCR5380_read(MODE_REG);
+    icr = NCR5380_read(INITIATOR_COMMAND_REG);
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    restore_flags(flags);
+    printk("STATUS_REG: %02x ", status);
+    for (i = 0; signals[i].mask ; ++i) 
+	if (status & signals[i].mask)
+	    printk(",%s", signals[i].name);
+    printk("\nBASR: %02x ", basr);
+    for (i = 0; basrs[i].mask ; ++i) 
+	if (basr & basrs[i].mask)
+	    printk(",%s", basrs[i].name);
+    printk("\nICR: %02x ", icr);
+    for (i = 0; icrs[i].mask; ++i) 
+	if (icr & icrs[i].mask)
+	    printk(",%s", icrs[i].name);
+    printk("\nMODE: %02x ", mr);
+    for (i = 0; mrs[i].mask; ++i) 
+	if (mr & mrs[i].mask)
+	    printk(",%s", mrs[i].name);
+    printk("\n");
+}
+
+static struct {
+    unsigned char value;
+    const char *name;
+} phases[] = {
+    {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+    {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+    {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/* 
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+    unsigned char status;
+    int i;
+
+    status = NCR5380_read(STATUS_REG);
+    if (!(status & SR_REQ)) 
+	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+    else {
+	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
+	    (phases[i].value != (status & PHASE_MASK)); ++i); 
+	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+    }
+}
+
+#else /* !NDEBUG */
+
+/* dummies... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
+ * 
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
+ */
+
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+static volatile int main_running = 0;
+static struct tq_struct NCR5380_tqueue = {
+    NULL,		/* next */
+    0,			/* sync */
+    (void (*)(void*))NCR5380_main,  /* routine, must have (void *) arg... */
+    NULL		/* data */
+};
+
+static __inline__ void queue_main(void)
+{
+    if (!main_running) {
+	/* If in interrupt and NCR5380_main() not already running,
+	   queue it on the 'immediate' task queue, to be processed
+	   immediately after the current interrupt processing has
+	   finished. */
+	queue_task(&NCR5380_tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+    }
+    /* else: nothing to do: the running NCR5380_main() will pick up
+       any newly queued command. */
+}
+
+
+static inline void NCR5380_all_init (void)
+{
+    static int done = 0;
+    if (!done) {
+	INI_PRINTK("scsi : NCR5380_all_init()\n");
+	done = 1;
+    }
+}
+
+ 
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ *	     options that were selected.
+ *
+ * Inputs : instance, pointer to this instance.  Unused.
+ */
+
+static void __init NCR5380_print_options (struct Scsi_Host *instance)
+{
+    printk(" generic options"
+#ifdef AUTOSENSE 
+    " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+    " REAL DMA"
+#endif
+#ifdef PARITY
+    " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+    " SCSI-2 TAGGED QUEUING"
+#endif
+    );
+    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ *	NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.  
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+    char *pr_bfr;
+    char *start;
+    int len;
+
+    NCR_PRINT(NDEBUG_ANY);
+    NCR_PRINT_PHASE(NDEBUG_ANY);
+
+    pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+    if (!pr_bfr) {
+	printk("NCR5380_print_status: no memory for print buffer\n");
+	return;
+    }
+    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+    pr_bfr[len] = 0;
+    printk("\n%s\n", pr_bfr);
+    free_page((unsigned long) pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(fmt,args...) \
+  do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+	 pos += sprintf(pos, fmt , ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+#ifndef NCR5380_proc_info
+static
+#endif
+int NCR5380_proc_info (char *buffer, char **start, off_t offset,
+		       int length, int hostno, int inout)
+{
+    char *pos = buffer;
+    struct Scsi_Host *instance;
+    struct NCR5380_hostdata *hostdata;
+    Scsi_Cmnd *ptr;
+    unsigned long flags;
+    off_t begin = 0;
+#define check_offset()				\
+    do {					\
+	if (pos - buffer < offset - begin) {	\
+	    begin += pos - buffer;		\
+	    pos = buffer;			\
+	}					\
+    } while (0)
+
+    for (instance = first_instance; instance && HOSTNO != hostno;
+	 instance = instance->next)
+	;
+    if (!instance)
+	return(-ESRCH);
+    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+    if (inout) { /* Has data been written to the file ? */
+	return(-ENOSYS);  /* Currently this is a no-op */
+    }
+    SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+    check_offset();
+    save_flags(flags);
+    cli();
+    SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+    check_offset();
+    if (!hostdata->connected)
+	SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+    else
+	pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+				pos, buffer, length);
+    SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+	 ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    restore_flags(flags);
+    *start = buffer + (offset - begin);
+    if (pos - buffer < offset - begin)
+	return 0;
+    else if (pos - buffer - (offset - begin) < length)
+	return pos - buffer - (offset - begin);
+    return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+    int i, s;
+    unsigned char *command;
+    SPRINTF("scsi%d: destination target %d, lun %d\n",
+	    H_NO(cmd), cmd->target, cmd->lun);
+    SPRINTF("        command = ");
+    command = cmd->cmnd;
+    SPRINTF("%2d (0x%02x)", command[0], command[0]);
+    for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+	SPRINTF(" %02x", command[i]);
+    SPRINTF("\n");
+    return pos;
+}
+
+
+/* 
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.  
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * 	set correctly.  I don't care about the irq and other fields. 
+ * 
+ */
+
+static void __init NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+    int i;
+    SETUP_HOSTDATA(instance);
+
+    NCR5380_all_init();
+
+    hostdata->aborted = 0;
+    hostdata->id_mask = 1 << instance->this_id;
+    hostdata->id_higher_mask = 0;
+    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+	if (i > hostdata->id_mask)
+	    hostdata->id_higher_mask |= i;
+    for (i = 0; i < 8; ++i)
+	hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+    init_tags();
+#endif
+#if defined (REAL_DMA)
+    hostdata->dma_len = 0;
+#endif
+    hostdata->targets_present = 0;
+    hostdata->connected = NULL;
+    hostdata->issue_queue = NULL;
+    hostdata->disconnected_queue = NULL;
+    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+    if (!the_template) {
+	the_template = instance->hostt;
+	first_instance = instance;
+    }
+	
+
+#ifndef AUTOSENSE
+    if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+	 printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+	        "        without AUTOSENSE option, contingent allegiance conditions may\n"
+	        "        be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+}
+
+/* 
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
+ *	void (*done)(Scsi_Cmnd *)) 
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	a pointer to the command descriptor.
+ * 
+ * Returns : 0
+ *
+ * Side effects : 
+ *      cmd is added to the per instance issue_queue, with minor 
+ *	twiddling done to the host specific fields of cmd.  If the 
+ *	main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+    SETUP_HOSTDATA(cmd->host);
+    Scsi_Cmnd *tmp;
+    unsigned long flags;
+    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+    switch (cmd->cmnd[0]) {
+    case WRITE_6:
+    case WRITE_10:
+	printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+	       H_NO(cmd));
+	cmd->result = (DID_ERROR << 16);
+	done(cmd);
+	return 0;
+    }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+    if (!hostdata->connected && !hostdata->issue_queue &&
+	!hostdata->disconnected_queue) {
+	hostdata->timebase = jiffies;
+    }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+		hostdata->pendingw++;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+		hostdata->pendingr++;
+		break;
+	}
+#endif
+
+    /* 
+     * We use the host_scribble field as a pointer to the next command  
+     * in a queue 
+     */
+
+    NEXT(cmd) = NULL;
+    cmd->scsi_done = done;
+
+    cmd->result = 0;
+
+
+    /* 
+     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+     * commands are added to the head of the queue since any command will
+     * clear the contingent allegiance condition that exists and the 
+     * sense data is only guaranteed to be valid while the condition exists.
+     */
+
+    save_flags(flags);
+    cli();
+    /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+     * Otherwise a running NCR5380_main may steal the lock.
+     * Lock before actually inserting due to fairness reasons explained in
+     * atari_scsi.c. If we insert first, then it's impossible for this driver
+     * to release the lock.
+     * Stop timer for this command while waiting for the lock, or timeouts
+     * may happen (and they really do), and it's no good if the command doesn't
+     * appear in any of the queues.
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which would
+     * alter queues and touch the lock.
+     */
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	LIST(cmd, hostdata->issue_queue);
+	NEXT(cmd) = hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+	     NEXT(tmp); tmp = NEXT(tmp))
+	    ;
+	LIST(cmd, tmp);
+	NEXT(tmp) = cmd;
+    }
+
+    restore_flags(flags);
+
+    QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+	      (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+    /* If queue_command() is called from an interrupt (real one or bottom
+     * half), we let queue_main() do the job of taking care about main. If it
+     * is already running, this is a no-op, else main will be queued.
+     *
+     * If we're not in an interrupt, we can call NCR5380_main()
+     * unconditionally, because it cannot be already running.
+     */
+    if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+	queue_main();
+    else
+	NCR5380_main();
+    return 0;
+}
+
+/*
+ * Function : NCR5380_main (void) 
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
+ *	be done on the NCR5380 host adapters in a system.  Both 
+ *	NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ *	in case it is not running.
+ * 
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
+ *  reenable them.  This prevents reentrancy and kernel stack overflow.
+ */ 	
+    
+static void NCR5380_main (void)
+{
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *instance = first_instance;
+    struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+    int done;
+    unsigned long flags;
+    
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set main_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     * this should prevent any race conditions.
+     * 
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which can
+     * alter queues and touch the Falcon lock.
+     */
+
+    /* Tell int handlers main() is now already executing.  Note that
+       no races are possible here. If an int comes in before
+       'main_running' is set here, and queues/executes main via the
+       task queue, it doesn't do any harm, just this instance of main
+       won't find any work left to do. */
+    if (main_running)
+    	return;
+    main_running = 1;
+
+    save_flags(flags);
+    do {
+	cli(); /* Freeze request queues */
+	done = 1;
+	
+	if (!hostdata->connected) {
+	    MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+	    /*
+	     * Search through the issue_queue for a command destined
+	     * for a target that's not busy.
+	     */
+#if (NDEBUG & NDEBUG_LISTS)
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+		 tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+		;
+	    if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+		 prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+		if (prev != tmp)
+		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
+			   tmp, tmp->target, hostdata->busy[tmp->target],
+			   tmp->lun);
+#endif
+		/*  When we find one, remove it from the issue queue. */
+		/* ++guenther: possible race with Falcon locking */
+		if (
+#ifdef SUPPORT_TAGS
+		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+		    !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+#endif
+		    ) {
+		    cli(); /* ++guenther: just to be sure, this must be atomic */
+		    if (prev) {
+		        REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+			NEXT(prev) = NEXT(tmp);
+		    } else {
+		        REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+			hostdata->issue_queue = NEXT(tmp);
+		    }
+		    NEXT(tmp) = NULL;
+		    
+		    /* reenable interrupts after finding one */
+		    restore_flags(flags);
+		    
+		    /* 
+		     * Attempt to establish an I_T_L nexus here. 
+		     * On success, instance->hostdata->connected is set.
+		     * On failure, we must add the command back to the
+		     *   issue queue so we can keep trying.	
+		     */
+		    MAIN_PRINTK("scsi%d: main(): command for target %d "
+				"lun %d removed from issue_queue\n",
+				HOSTNO, tmp->target, tmp->lun);
+		    /* 
+		     * REQUEST SENSE commands are issued without tagged
+		     * queueing, even on SCSI-II devices because the 
+		     * contingent allegiance condition exists for the 
+		     * entire unit.
+		     */
+		    /* ++roman: ...and the standard also requires that
+		     * REQUEST SENSE command are untagged.
+		     */
+		    
+#ifdef SUPPORT_TAGS
+		    cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+		    if (!NCR5380_select(instance, tmp, 
+			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
+			    TAG_NEXT)) {
+			break;
+		    } else {
+			cli();
+			LIST(tmp, hostdata->issue_queue);
+			NEXT(tmp) = hostdata->issue_queue;
+			hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+			cmd_free_tag( tmp );
+#endif
+			restore_flags(flags);
+			MAIN_PRINTK("scsi%d: main(): select() failed, "
+				    "returned to issue_queue\n", HOSTNO);
+			if (hostdata->connected)
+			    break;
+		    }
+		} /* if target/lun/target queue is not busy */
+	    } /* for issue_queue */
+	} /* if (!hostdata->connected) */
+	if (hostdata->connected 
+#ifdef REAL_DMA
+	    && !hostdata->dma_len
+#endif
+	    ) {
+	    restore_flags(flags);
+	    MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+			HOSTNO);
+	    NCR5380_information_transfer(instance);
+	    MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+	    done = 0;
+	}
+    } while (!done);
+
+    /* Better allow ints _after_ 'main_running' has been cleared, else
+       an interrupt could believe we'll pick up the work it left for
+       us, but we won't see it anymore here... */
+    main_running = 0;
+    restore_flags(flags);
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ *	mismatch occurs (which would finish the DMA transfer).  
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+    SETUP_HOSTDATA(instance);
+    int           transfered;
+    unsigned char **data;
+    volatile int  *count;
+
+    if (!hostdata->connected) {
+	printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+	       "no connected cmd\n", HOSTNO);
+	return;
+    }
+
+    DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+	       NCR5380_read(STATUS_REG));
+
+    if((sun3scsi_dma_finish())) {
+	    printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
+	    printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+	    printk("error was produced.\n");
+	    machine_halt();
+    }
+
+    /* make sure we're not stuck in a data phase */
+    if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH |
+					    BASR_ACK)) ==
+       (BASR_PHASE_MATCH | BASR_ACK)) {
+	    printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
+	    printk("scsi%d: bus stuck in data phase -- probably a
+ single byte overrun!\n", HOSTNO); 
+	    printk("not prepared for this error!\n");
+	    printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+	    printk("error was produced.\n");
+	    machine_halt();
+    }
+
+
+
+    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+    hostdata->dma_len = 0;
+
+    data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+    count = &(hostdata->connected->SCp.this_residual);
+    *data += transfered;
+    *count -= transfered;
+
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ * 
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ *	from the disconnected queue, and restarting NCR5380_main() 
+ *	as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct Scsi_Host *instance = first_instance;
+    int done = 1;
+    unsigned char basr;
+
+    INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+    /* Look for pending interrupts */
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+    /* dispatch to appropriate routine if found and done=0 */
+    if (basr & BASR_IRQ) {
+	NCR_PRINT(NDEBUG_INTR);
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+	    done = 0;
+	    ENABLE_IRQ();
+	    INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+	    NCR5380_reselect(instance);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if (basr & BASR_PARITY_ERROR) {
+	    INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+	    INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else {
+	    /*  
+	     * The rest of the interrupt conditions can occur only during a
+	     * DMA transfer
+	     */
+
+#if defined(REAL_DMA)
+	    /*
+	     * We should only get PHASE MISMATCH and EOP interrupts if we have
+	     * DMA enabled, so do a sanity check based on the current setting
+	     * of the MODE register.
+	     */
+
+	    if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+		((basr & BASR_END_DMA_TRANSFER) || 
+		 !(basr & BASR_PHASE_MATCH))) {
+		    
+		INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+		NCR5380_dma_complete( instance );
+		done = 0;
+		ENABLE_IRQ();
+	    } else
+#endif /* REAL_DMA */
+	    {
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+		if (basr & BASR_PHASE_MATCH)
+		    printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+			   HOSTNO, basr, NCR5380_read(MODE_REG),
+			   NCR5380_read(STATUS_REG));
+		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    }
+	} /* if !(SELECTION || PARITY) */
+    } /* BASR & IRQ */
+    else {
+
+	printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    }
+    
+    if (!done) {
+	INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+	/* Put a call to NCR5380_main() on the queue... */
+	queue_main();
+    }
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+		hostdata->pendingw--;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+		hostdata->pendingr--;
+		break;
+	}
+}
+#endif
+
+/* 
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+ *	int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ *	including ARBITRATION, SELECTION, and initial message out for 
+ *	IDENTIFY and queue messages. 
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this 
+ * 	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
+ *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ *	the command that is presently connected.
+ * 
+ * Returns : -1 if selection could not execute for some reason,
+ *	0 if selection succeeded or failed because the target 
+ * 	did not respond.
+ *
+ * Side effects : 
+ * 	If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ *		with registers as they should have been on entry - ie
+ *		SELECT_ENABLE will be set appropriately, the NCR5380
+ *		will cease to drive any SCSI bus signals.
+ *
+ *	If successful : I_T_L or I_T_L_Q nexus will be established, 
+ *		instance->connected will be set to cmd.  
+ * 		SELECT interrupt will be disabled.
+ *
+ *	If failed (no target) : cmd->scsi_done() will be called, and the 
+ *		cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char tmp[3], phase;
+    unsigned char *data;
+    int len;
+    unsigned long timeout;
+    unsigned long flags;
+
+    hostdata->restart_select = 0;
+    NCR_PRINT(NDEBUG_ARBITRATION);
+    ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+	       instance->this_id);
+
+    /* 
+     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+     * data bus during SELECTION.
+     */
+
+    save_flags(flags);
+    cli();
+    if (hostdata->connected) {
+	restore_flags(flags);
+	return -1;
+    }
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+    /* 
+     * Start arbitration.
+     */
+    
+    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+    NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+    restore_flags(flags);
+
+    /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+    {
+      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	   && time_before(jiffies, timeout) && !hostdata->connected)
+	;
+      if (time_after_eq(jiffies, timeout))
+      {
+	printk("scsi : arbitration timeout at %d\n", __LINE__);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return -1;
+      }
+    }
+#else /* NCR_TIMEOUT */
+    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	 && !hostdata->connected);
+#endif
+
+    ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	return -1;
+    }
+    /* 
+     * The arbitration delay is 2.2us, but this is a minimum and there is 
+     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+     * the integral nature of udelay().
+     *
+     */
+
+    udelay(3);
+
+    /* Check for lost arbitration */
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+		   HOSTNO);
+	return -1;
+    }
+
+     /* after/during arbitration, BSY should be asserted.
+	IBM DPES-31080 Version S31Q works now */
+     /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+					 ICR_ASSERT_BSY ) ;
+    
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+		   HOSTNO);
+	return -1;
+    }
+
+    /* 
+     * Again, bus clear + bus settle time is 1.2us, however, this is 
+     * a minimum so we'll udelay ceil(1.2)
+     */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    /* ++roman: But some targets (see above :-) seem to need a bit more... */
+    udelay(15);
+#else
+    udelay(2);
+#endif
+    
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+    /* 
+     * Now that we have won arbitration, start Selection process, asserting 
+     * the host and target ID's on the SCSI bus.
+     */
+
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+
+    /* 
+     * Raise ATN while SEL is true before BSY goes false from arbitration,
+     * since this is the only way to guarantee that we'll get a MESSAGE OUT
+     * phase immediately after selection.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
+	ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+    NCR5380_write(MODE_REG, MR_BASE);
+
+    /* 
+     * Reselect interrupts must be turned off prior to the dropping of BSY,
+     * otherwise we will trigger an interrupt.
+     */
+
+    if (hostdata->connected) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    /*
+     * The initiator shall then wait at least two deskew delays and release 
+     * the BSY signal.
+     */
+    udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
+
+    /* Reset BSY */
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
+	ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+    /* 
+     * Something weird happens when we cease to drive BSY - looks
+     * like the board/chip is letting us do another read before the 
+     * appropriate propagation delay has expired, and we're confusing
+     * a BSY signal from ourselves as the target's response to SELECTION.
+     *
+     * A small delay (the 'C++' frontend breaks the pipeline with an
+     * unnecessary jump, making it work on my 386-33/Trantor T128, the
+     * tighter 'C' code breaks and requires this) solves the problem - 
+     * the 1 us delay is arbitrary, and only used because this delay will 
+     * be the same on other platforms and since it works here, it should 
+     * work there.
+     *
+     * wingel suggests that this could be due to failing to wait
+     * one deskew delay.
+     */
+
+    udelay(1);
+
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+
+    /* 
+     * The SCSI specification calls for a 250 ms timeout for the actual 
+     * selection.
+     */
+
+    timeout = jiffies + 25; 
+
+    /* 
+     * XXX very interesting - we're seeing a bounce where the BSY we 
+     * asserted is being reflected / still asserted (propagation delay?)
+     * and it's detecting as true.  Sigh.
+     */
+
+#if 0
+    /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+     * IO while SEL is true. But again, there are some disks out the in the
+     * world that do that nevertheless. (Somebody claimed that this announces
+     * reselection capability of the target.) So we better skip that test and
+     * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+     */
+
+    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & 
+	(SR_BSY | SR_IO)));
+
+    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
+	    (SR_SEL | SR_IO)) {
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	    NCR5380_reselect(instance);
+	    printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+		    HOSTNO);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+    }
+#else
+    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+    /* 
+     * No less than two deskew delays after the initiator detects the 
+     * BSY signal is true, it shall release the SEL signal and may 
+     * change the DATA BUS.                                     -wingel
+     */
+
+    udelay(1);
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	if (hostdata->targets_present & (1 << cmd->target)) {
+	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+	    if (hostdata->restart_select)
+		printk(KERN_NOTICE "\trestart select\n");
+	    NCR_PRINT(NDEBUG_ANY);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+	}
+	cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+	collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+	cmd_free_tag( cmd );
+#endif
+	cmd->scsi_done(cmd);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return 0;
+    } 
+
+    hostdata->targets_present |= (1 << cmd->target);
+
+    /*
+     * Since we followed the SCSI spec, and raised ATN while SEL 
+     * was true but before BSY was false during selection, the information
+     * transfer phase should be a MESSAGE OUT phase so that we can send the
+     * IDENTIFY message.
+     * 
+     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+     * message (2 bytes) with a tag ID that we increment with every command
+     * until it wraps back to 0.
+     *
+     * XXX - it turns out that there are some broken SCSI-II devices,
+     *	     which claim to support tagged queuing but fail when more than
+     *	     some number of commands are issued at once.
+     */
+
+    /* Wait for start of REQ/ACK handshake */
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+	       HOSTNO, cmd->target);
+    tmp[0] = IDENTIFY(1, cmd->lun);
+
+#ifdef SUPPORT_TAGS
+    if (cmd->tag != TAG_NONE) {
+	tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+	tmp[2] = cmd->tag;
+	len = 3;
+    } else 
+	len = 1;
+#else
+    len = 1;
+    cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+    /* Send message(s) */
+    data = tmp;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+    SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+    /* XXX need to handle errors here */
+    hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+    hostdata->busy[cmd->target] |= (1 << cmd->lun);
+#endif    
+
+    initialize_SCp(cmd);
+
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes are transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it 
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    register unsigned char p = *phase, tmp;
+    register int c = *count;
+    register unsigned char *d = *data;
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+    do {
+	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+	HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+	    PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+	    NCR_PRINT_PHASE(NDEBUG_PIO);
+	    break;
+	}
+
+	/* Do actual transfer from SCSI bus to / from memory */
+	if (!(p & SR_IO)) 
+	    NCR5380_write(OUTPUT_DATA_REG, *d);
+	else 
+	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+	++d;
+
+	/* 
+	 * The SCSI standard suggests that in MSGOUT phase, the initiator
+	 * should drop ATN on the last byte of the message phase
+	 * after REQ has been asserted for the handshake but before
+	 * the initiator raises ACK.
+	 */
+
+	if (!(p & SR_IO)) {
+	    if (!((p & SR_MSG) && c > 1)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+	    } else {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+	    }
+	} else {
+	    NCR_PRINT(NDEBUG_PIO);
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+	}
+
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+	HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking : 
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the 
+ *	message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the  
+ *	message.  We must exit with ACK asserted, so that the calling
+ *	code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
+	if (!(p == PHASE_MSGIN && c == 1)) {  
+	    if (p == PHASE_MSGOUT && c > 1)
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	    else
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	} 
+    } while (--c);
+
+    PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+    *count = c;
+    *data = d;
+    tmp = NCR5380_read(STATUS_REG);
+    /* The phase read from the bus is valid if either REQ is (already)
+     * asserted or if ACK hasn't been released yet. The latter is the case if
+     * we're in MSGIN and all wanted bytes have been received. */
+    if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+	*phase = tmp & PHASE_MASK;
+    else 
+	*phase = PHASE_UNKNOWN;
+
+    if (!c || (*phase == p))
+	return 0;
+    else 
+	return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ * 	called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host) 
+{
+    unsigned char tmp, *msgptr, phase;
+    int len;
+
+    /* Request message out phase */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    /* 
+     * Wait for the target to indicate a valid phase by asserting 
+     * REQ.  Once this happens, we'll have either a MSGOUT phase 
+     * and can immediately send the ABORT message, or we'll have some 
+     * other phase and will have to source/sink data.
+     * 
+     * We really don't care what value was on the bus or what value
+     * the target sees, so we just handshake.
+     */
+    
+    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		      ICR_ASSERT_ACK);
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+    }
+   
+    tmp = ABORT;
+    msgptr = &tmp;
+    len = 1;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+    /*
+     * If we got here, and the command completed successfully,
+     * we're about to go into bus free state.
+     */
+
+    return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA)
+/* 
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ *	or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes or transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    SETUP_HOSTDATA(instance);
+    register int c = *count;
+    register unsigned char p = *phase;
+    unsigned long flags;
+
+    /* sanity check */
+    if(!sun3_dma_setup_done) {
+	 printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
+	 machine_halt();
+    }
+
+    hostdata->dma_len = c;
+
+    DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
+	       c, (p & SR_IO) ? "to" : "from", d);
+
+    /* netbsd turns off ints here, why not be safe and do it too */
+    save_flags(flags);
+    cli();
+    
+    /* send start chain */
+    sun3_udc_write(UDC_CHN_START, UDC_CSR);
+    
+    if (p & SR_IO) {
+	    NCR5380_write(TARGET_COMMAND_REG, 1);
+	    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    NCR5380_write(INITIATOR_COMMAND_REG, 0);
+	    NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+	    NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+    } else {
+	    NCR5380_write(TARGET_COMMAND_REG, 0);
+	    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
+	    NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+	    NCR5380_write(START_DMA_SEND_REG, 0);
+    }
+
+    restore_flags(flags);
+
+    sun3_dma_active = 1;
+    return 0;
+}
+#endif /* defined(REAL_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target 
+ * 	directs us to.  Operates on the currently connected command, 
+ *	instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be 
+ *	modified if a command disconnects, *instance->connected will
+ *	change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here 
+ * 	to recover from an unexpected bus free condition.
+ */
+ 
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned long flags;
+    unsigned char msgout = NOP;
+    int sink = 0;
+    int len;
+#if defined(REAL_DMA)
+    int transfersize;
+#endif
+    unsigned char *data;
+    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+    while (1) {
+	tmp = NCR5380_read(STATUS_REG);
+	/* We only have a valid SCSI phase when REQ is asserted */
+	if (tmp & SR_REQ) {
+	    phase = (tmp & PHASE_MASK); 
+ 	    if (phase != old_phase) {
+		old_phase = phase;
+		NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+	    }
+
+	    if(phase == PHASE_CMDOUT) {
+		    void *d;
+		    unsigned long count;
+
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+			count = cmd->SCp.buffer->length;
+			d = cmd->SCp.buffer->address;
+		} else {
+			count = cmd->SCp.this_residual;
+			d = cmd->SCp.ptr;
+		}
+#ifdef REAL_DMA
+		/* this command setup for dma yet? */
+		if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+						  != cmd))
+		{
+			sun3scsi_dma_setup(d, count,
+					   cmd->request.cmd);
+			sun3_dma_setup_done = cmd;
+		}
+#endif
+	    }
+
+	    
+	    if (sink && (phase != PHASE_MSGOUT)) {
+		NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		    ICR_ASSERT_ACK);
+		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_ATN);
+		sink = 0;
+		continue;
+	    }
+
+	    switch (phase) {
+	    case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+		printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+		       "aborted\n", HOSTNO);
+		sink = 1;
+		do_abort(instance);
+		cmd->result = DID_ERROR  << 16;
+		cmd->done(cmd);
+		return;
+#endif
+	    case PHASE_DATAIN:
+		/* 
+		 * If there is no room left in the current buffer in the
+		 * scatter-gather list, move onto the next one.
+		 */
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		    ++cmd->SCp.buffer;
+		    --cmd->SCp.buffers_residual;
+		    cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		    cmd->SCp.ptr = cmd->SCp.buffer->address;
+
+		    /* ++roman: Try to merge some scatter-buffers if
+		     * they are at contiguous physical addresses.
+		     */
+//		    merge_contiguous_buffers( cmd );
+		    INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+			       HOSTNO, cmd->SCp.this_residual,
+			       cmd->SCp.buffers_residual);
+		}
+
+		/*
+		 * The preferred transfer method is going to be 
+		 * PSEUDO-DMA for systems that are strictly PIO,
+		 * since we can let the hardware do the handshaking.
+		 *
+		 * For this to work, we need to know the transfersize
+		 * ahead of time, since the pseudo-DMA code will sit
+		 * in an unconditional loop.
+		 */
+
+/* ++roman: I suggest, this should be
+ *   #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA)
+//		if (!cmd->device->borken &&
+		if((transfersize =
+		    NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) {
+		    len = transfersize;
+		    cmd->SCp.phase = phase;
+
+		    if (NCR5380_transfer_dma(instance, &phase,
+			&len, (unsigned char **) &cmd->SCp.ptr)) {
+			/*
+			 * If the watchdog timer fires, all future
+			 * accesses to this device will use the
+			 * polled-IO. */ 
+			printk(KERN_NOTICE "scsi%d: switching target %d "
+			       "lun %d to slow handshake\n", HOSTNO,
+			       cmd->target, cmd->lun);
+			cmd->device->borken = 1;
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			    ICR_ASSERT_ATN);
+			sink = 1;
+			do_abort(instance);
+			cmd->result = DID_ERROR  << 16;
+			cmd->done(cmd);
+			/* XXX - need to source or sink data here, as appropriate */
+		    } else {
+#ifdef REAL_DMA
+			/* ++roman: When using real DMA,
+			 * information_transfer() should return after
+			 * starting DMA since it has nothing more to
+			 * do.
+			 */
+				    return;
+#else			
+			cmd->SCp.this_residual -= transfersize - len;
+#endif
+		    }
+		} else 
+#endif /* defined(REAL_DMA) */
+		  NCR5380_transfer_pio(instance, &phase, 
+		    (int *) &cmd->SCp.this_residual, (unsigned char **)
+		    &cmd->SCp.ptr);
+#ifdef REAL_DMA
+		/* if we had intended to dma that command clear it */
+		if(sun3_dma_setup_done == cmd)
+			sun3_dma_setup_done = NULL;
+#endif
+
+		break;
+	    case PHASE_MSGIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_write(SELECT_ENABLE_REG, 0); 	/* disable reselects */
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Message = tmp;
+
+		switch (tmp) {
+		/*
+		 * Linking lets us reduce the time required to get the 
+		 * next command out to the device, hopefully this will
+		 * mean we don't waste another revolution due to the delays
+		 * required by ARBITRATION and another SELECTION.
+		 *
+		 * In the current implementation proposal, low level drivers
+		 * merely have to start the next command, pointed to by 
+		 * next_link, done() is called as with unlinked commands.
+		 */
+#ifdef LINKED
+		case LINKED_CMD_COMPLETE:
+		case LINKED_FLG_CMD_COMPLETE:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    
+		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
+			       "complete.\n", HOSTNO, cmd->target, cmd->lun);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /*
+		     * Sanity check : A linked command should only terminate
+		     * with one of these messages if there are more linked
+		     * commands available.
+		     */
+
+		    if (!cmd->next_link) {
+			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
+				"linked command complete, no next_link\n",
+				HOSTNO, cmd->target, cmd->lun);
+			    sink = 1;
+			    do_abort (instance);
+			    return;
+		    }
+
+		    initialize_SCp(cmd->next_link);
+		    /* The next command is still part of this process; copy it
+		     * and don't free it! */
+		    cmd->next_link->tag = cmd->tag;
+		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
+			       "done, calling scsi_done().\n",
+			       HOSTNO, cmd->target, cmd->lun);
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    cmd = hostdata->connected;
+		    break;
+#endif /* def LINKED */
+		case ABORT:
+		case COMMAND_COMPLETE: 
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    hostdata->connected = NULL;
+		    QU_PRINTK("scsi%d: command for target %d, lun %d "
+			      "completed\n", HOSTNO, cmd->target, cmd->lun);
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+			/* Turn a QUEUE FULL status into BUSY, I think the
+			 * mid level cannot handle QUEUE FULL :-( (The
+			 * command is retried after BUSY). Also update our
+			 * queue size to the number of currently issued
+			 * commands now.
+			 */
+			/* ++Andreas: the mid level code knows about
+			   QUEUE_FULL now. */
+			TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+			TAG_PRINTK("scsi%d: target %d lun %d returned "
+				   "QUEUE_FULL after %d commands\n",
+				   HOSTNO, cmd->target, cmd->lun,
+				   ta->nr_allocated);
+			if (ta->queue_size > ta->nr_allocated)
+			    ta->nr_allocated = ta->queue_size;
+		    }
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+		    /* 
+		     * I'm not sure what the correct thing to do here is : 
+		     * 
+		     * If the command that just executed is NOT a request 
+		     * sense, the obvious thing to do is to set the result
+		     * code to the values of the stored parameters.
+		     * 
+		     * If it was a REQUEST SENSE command, we need some way to
+		     * differentiate between the failure code of the original
+		     * and the failure code of the REQUEST sense - the obvious
+		     * case is success, where we fall through and leave the
+		     * result code unchanged.
+		     * 
+		     * The non-obvious place is where the REQUEST SENSE failed
+		     */
+
+		    if (cmd->cmnd[0] != REQUEST_SENSE) 
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    else if (status_byte(cmd->SCp.Status) != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		    
+#ifdef AUTOSENSE
+		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
+			(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+			ASEN_PRINTK("scsi%d: performing request sense\n",
+				    HOSTNO);
+			cmd->cmnd[0] = REQUEST_SENSE;
+			cmd->cmnd[1] &= 0xe0;
+			cmd->cmnd[2] = 0;
+			cmd->cmnd[3] = 0;
+			cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+			cmd->cmnd[5] = 0;
+			cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+			cmd->use_sg = 0;
+			/* this is initialized from initialize_SCp 
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.buffers_residual = 0;
+			*/
+			cmd->request_buffer = (char *) cmd->sense_buffer;
+			cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+			save_flags(flags);
+			cli();
+			LIST(cmd,hostdata->issue_queue);
+			NEXT(cmd) = hostdata->issue_queue;
+		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+		        restore_flags(flags);
+			QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+				  "issue queue\n", H_NO(cmd));
+		   } else
+#endif /* def AUTOSENSE */
+		   {
+#ifdef NCR5380_STATS
+		       collect_stats(hostdata, cmd);
+#endif
+		       cmd->scsi_done(cmd);
+		    }
+
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+		    
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+			barrier();
+
+		    return;
+		case MESSAGE_REJECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    switch (hostdata->last_message) {
+		    case HEAD_OF_QUEUE_TAG:
+		    case ORDERED_QUEUE_TAG:
+		    case SIMPLE_QUEUE_TAG:
+			/* The target obviously doesn't support tagged
+			 * queuing, even though it announced this ability in
+			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+			 * clear 'tagged_supported' and lock the LUN, since
+			 * the command is treated as untagged further on.
+			 */
+			cmd->device->tagged_supported = 0;
+			hostdata->busy[cmd->target] |= (1 << cmd->lun);
+			cmd->tag = TAG_NONE;
+			TAG_PRINTK("scsi%d: target %d lun %d rejected "
+				   "QUEUE_TAG message; tagged queuing "
+				   "disabled\n",
+				   HOSTNO, cmd->target, cmd->lun);
+			break;
+		    }
+		    break;
+		case DISCONNECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    save_flags(flags);
+		    cli();
+		    cmd->device->disconnect = 1;
+		    LIST(cmd,hostdata->disconnected_queue);
+		    NEXT(cmd) = hostdata->disconnected_queue;
+		    hostdata->connected = NULL;
+		    hostdata->disconnected_queue = cmd;
+		    restore_flags(flags);
+		    QU_PRINTK("scsi%d: command for target %d lun %d was "
+			      "moved from connected to the "
+			      "disconnected_queue\n", HOSTNO, 
+			      cmd->target, cmd->lun);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* Wait for bus free to avoid nasty timeouts */
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+		    	barrier();
+		    return;
+		/* 
+		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+		 * operation, in violation of the SCSI spec so we can safely 
+		 * ignore SAVE/RESTORE pointers calls.
+		 *
+		 * Unfortunately, some disks violate the SCSI spec and 
+		 * don't issue the required SAVE_POINTERS message before
+		 * disconnecting, and we have to break spec to remain 
+		 * compatible.
+		 */
+		case SAVE_POINTERS:
+		case RESTORE_POINTERS:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    break;
+		case EXTENDED_MESSAGE:
+/* 
+ * Extended messages are sent in the following format :
+ * Byte 	
+ * 0		EXTENDED_MESSAGE == 1
+ * 1		length (includes one byte for code, doesn't 
+ *		include first two bytes)
+ * 2 		code
+ * 3..length+1	arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.  
+ */
+		    extended_msg[0] = EXTENDED_MESSAGE;
+		    /* Accept first byte by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+		    EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+		    len = 2;
+		    data = extended_msg + 1;
+		    phase = PHASE_MSGIN;
+		    NCR5380_transfer_pio(instance, &phase, &len, &data);
+		    EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+			       (int)extended_msg[1], (int)extended_msg[2]);
+
+		    if (!len && extended_msg[1] <= 
+			(sizeof (extended_msg) - 1)) {
+			/* Accept third byte by clearing ACK */
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+			len = extended_msg[1] - 1;
+			data = extended_msg + 3;
+			phase = PHASE_MSGIN;
+
+			NCR5380_transfer_pio(instance, &phase, &len, &data);
+			EXT_PRINTK("scsi%d: message received, residual %d\n",
+				   HOSTNO, len);
+
+			switch (extended_msg[2]) {
+			case EXTENDED_SDTR:
+			case EXTENDED_WDTR:
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			    tmp = 0;
+			}
+		    } else if (len) {
+			printk(KERN_NOTICE "scsi%d: error receiving "
+			       "extended message\n", HOSTNO);
+			tmp = 0;
+		    } else {
+			printk(KERN_NOTICE "scsi%d: extended message "
+			       "code %02x length %d is too long\n",
+			       HOSTNO, extended_msg[2], extended_msg[1]);
+			tmp = 0;
+		    }
+		/* Fall through to reject message */
+
+		/* 
+  		 * If we get something weird that we aren't expecting, 
+ 		 * reject it.
+		 */
+		default:
+		    if (!tmp) {
+			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+			print_msg (extended_msg);
+			printk("\n");
+		    } else if (tmp != EXTENDED_MESSAGE)
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "message %02x from target %d, lun %d\n",
+			       HOSTNO, tmp, cmd->target, cmd->lun);
+		    else
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "extended message "
+			       "code %02x, length %d from target %d, lun %d\n",
+			       HOSTNO, extended_msg[1], extended_msg[0],
+			       cmd->target, cmd->lun);
+   
+
+		    msgout = MESSAGE_REJECT;
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_ATN);
+		    break;
+		} /* switch (tmp) */
+		break;
+	    case PHASE_MSGOUT:
+		len = 1;
+		data = &msgout;
+		hostdata->last_message = msgout;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    hostdata->connected = NULL;
+		    cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    return;
+		}
+		msgout = NOP;
+		break;
+	    case PHASE_CMDOUT:
+		len = cmd->cmd_len;
+		data = cmd->cmnd;
+		/* 
+		 * XXX for performance reasons, on machines with a 
+		 * PSEUDO-DMA architecture we should probably 
+		 * use the dma transfer function.  
+		 */
+		NCR5380_transfer_pio(instance, &phase, &len, 
+		    &data);
+		break;
+	    case PHASE_STATIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Status = tmp;
+		break;
+	    default:
+		printk("scsi%d: unknown phase\n", HOSTNO);
+		NCR_PRINT(NDEBUG_ANY);
+	    } /* switch(phase) */
+	} /* if (tmp * SR_REQ) */ 
+    } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected 
+ *	field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
+ *	nexus has been reestablished,
+ *	
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+/* it might eventually prove necessary to do a dma setup on
+   reselection, but it doesn't seem to be needed now -- sam */
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char target_mask;
+    unsigned char lun;
+#ifdef SUPPORT_TAGS
+    unsigned char tag;
+#endif
+    unsigned char msg[3];
+    Scsi_Cmnd *tmp = NULL, *prev;
+/*    unsigned long flags; */
+
+    /*
+     * Disable arbitration, etc. since the host adapter obviously
+     * lost, and tell an interrupted NCR5380_select() to restart.
+     */
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    hostdata->restart_select = 1;
+
+    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+    RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+    /* 
+     * At this point, we have detected that our SCSI ID is on the bus,
+     * SEL is true and BSY was false for at least one bus settle delay
+     * (400 ns).
+     *
+     * We must assert BSY ourselves, until the target drops the SEL
+     * signal.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+    
+    while (NCR5380_read(STATUS_REG) & SR_SEL);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    /*
+     * Wait for target to go into MSGIN.
+     */
+
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+#if 1
+    // acknowledge toggle to MSGIN
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
+
+    // peek at the byte without really hitting the bus
+    msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
+#endif
+
+    if (!msg[0] & 0x80) {
+	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+	print_msg(msg);
+	do_abort(instance);
+	return;
+    }
+    lun = (msg[0] & 0x07);
+
+    /* 
+     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
+     * just reestablished, and remove it from the disconnected queue.
+     */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
+	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
+	if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+#ifdef SUPPORT_TAGS
+	    && (tag == tmp->tag) 
+#endif
+	    ) {
+	    if (prev) {
+		REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+		NEXT(prev) = NEXT(tmp);
+	    } else {
+		REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+		hostdata->disconnected_queue = NEXT(tmp);
+	    }
+	    NEXT(tmp) = NULL;
+	    break;
+	}
+    }
+    
+    if (!tmp) {
+	printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+		"tag %d "
+#endif
+		"not in disconnected_queue.\n",
+		HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+		, tag
+#endif
+		);
+	/* 
+	 * Since we have an established nexus that we can't do anything
+	 * with, we must abort it.  
+	 */
+	do_abort(instance);
+	return;
+    }
+#if 1
+    /* engage dma setup for the command we just saw */
+    {
+	    void *d;
+		    unsigned long count;
+
+		if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
+			count = tmp->SCp.buffer->length;
+			d = tmp->SCp.buffer->address;
+		} else {
+			count = tmp->SCp.this_residual;
+			d = tmp->SCp.ptr;
+		}
+#ifdef REAL_DMA		
+		/* setup this command for dma if not already */
+		if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+						  != tmp))
+		{
+			sun3scsi_dma_setup(d, count,
+					   tmp->request.cmd);
+			sun3_dma_setup_done = tmp;
+		}
+#endif
+    }
+#endif
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+    /* Accept message by clearing ACK */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+#ifdef SUPPORT_TAGS
+    /* If the phase is still MSGIN, the target wants to send some more
+     * messages. In case it supports tagged queuing, this is probably a
+     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+     */
+    tag = TAG_NONE;
+    if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+	/* Accept previous IDENTIFY message by clearing ACK */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	len = 2;
+	data = msg+1;
+	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+	    msg[1] == SIMPLE_QUEUE_TAG)
+	    tag = msg[2];
+	TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+		   "reselection\n", HOSTNO, target_mask, lun, tag);
+    }
+#endif
+    
+    hostdata->connected = tmp;
+    RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+	       HOSTNO, tmp->target, tmp->lun, tmp->tag);
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
+ * 	host byte of the result field to, if zero DID_ABORTED is 
+ *	used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently 
+ * 	 connected, you have to wait for it to complete.  If this is 
+ *	 a problem, we could implement longjmp() / setjmp(), setjmp()
+ * 	 called where the loop started in NCR5380_main().
+ */
+
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+    struct Scsi_Host *instance = cmd->host;
+    SETUP_HOSTDATA(instance);
+    Scsi_Cmnd *tmp, **prev;
+    unsigned long flags;
+
+    printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+    print_Scsi_Cmnd (cmd);
+
+    NCR5380_print_status (instance);
+
+    save_flags(flags);
+    cli();
+    
+    ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+		NCR5380_read(BUS_AND_STATUS_REG),
+		NCR5380_read(STATUS_REG));
+
+#if 1
+/* 
+ * Case 1 : If the command is the currently executing command, 
+ * we'll set the aborted flag and return control so that 
+ * information transfer routine can exit cleanly.
+ */
+
+    if (hostdata->connected == cmd) {
+
+	ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+/* 
+ * Since we can't change phases until we've completed the current 
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/* 
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */ 
+
+	if (do_abort(instance) == 0) {
+	  hostdata->aborted = 1;
+	  hostdata->connected = NULL;
+	  cmd->result = DID_ABORT << 16;
+#ifdef SUPPORT_TAGS
+	  cmd_free_tag( cmd );
+#else
+	  hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+	  restore_flags(flags);
+	  cmd->scsi_done(cmd);
+	  return SCSI_ABORT_SUCCESS;
+	} else {
+/*	  restore_flags(flags); */
+	  printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+	  return SCSI_ABORT_ERROR;
+	} 
+   }
+#endif
+
+/* 
+ * Case 2 : If the command hasn't been issued yet, we simply remove it 
+ * 	    from the issue queue.
+ */
+    for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), 
+	tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+	tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+	if (cmd == tmp) {
+	    REMOVE(5, *prev, tmp, NEXT(tmp));
+	    (*prev) = NEXT(tmp);
+	    NEXT(tmp) = NULL;
+	    tmp->result = DID_ABORT << 16;
+	    restore_flags(flags);
+	    ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+			HOSTNO);
+	    /* Tagged queuing note: no tag to free here, hasn't been assigned
+	     * yet... */
+	    tmp->scsi_done(tmp);
+	    return SCSI_ABORT_SUCCESS;
+	}
+
+/* 
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ *	    and let the high level SCSI driver retry at a later time or 
+ *	    issue a reset.
+ *
+ *	    Timeouts, and therefore aborted commands, will be highly unlikely
+ *          and handling them cleanly in this situation would make the common
+ *	    case of noresets less efficient, and would pollute our code.  So,
+ *	    we fail.
+ */
+
+    if (hostdata->connected) {
+	restore_flags(flags);
+	ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+        return SCSI_ABORT_SNOOZE;
+    }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and 
+ * 	there are no connected commands, we reconnect the I_T_L or 
+ *	I_T_L_Q nexus associated with it, go into message out, and send 
+ *      an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select().  The easiest way to implement this 
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we 
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that 
+ * device reselected.
+ * 
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+	 tmp = NEXT(tmp)) 
+        if (cmd == tmp) {
+            restore_flags(flags);
+	    ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+  
+            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
+		return SCSI_ABORT_BUSY;
+
+	    ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+	    do_abort (instance);
+
+	    save_flags(flags);
+	    cli();
+	    for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
+		tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+		tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+		    if (cmd == tmp) {
+		    REMOVE(5, *prev, tmp, NEXT(tmp));
+		    *prev = NEXT(tmp);
+		    NEXT(tmp) = NULL;
+		    tmp->result = DID_ABORT << 16;
+		    /* We must unlock the tag/LUN immediately here, since the
+		     * target goes to BUS FREE and doesn't send us another
+		     * message (COMMAND_COMPLETE or the like)
+		     */
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( tmp );
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    restore_flags(flags);
+		    tmp->scsi_done(tmp);
+		    return SCSI_ABORT_SUCCESS;
+		}
+	}
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of 
+ *	    the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+    restore_flags(flags);
+    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+           KERN_INFO "        before abortion\n", HOSTNO); 
+
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/* 
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * 
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */ 
+
+int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+    SETUP_HOSTDATA(cmd->host);
+    int           i;
+    unsigned long flags;
+#if 1
+    Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+
+    NCR5380_print_status (cmd->host);
+
+    /* get in phase */
+    NCR5380_write( TARGET_COMMAND_REG,
+		   PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+    /* assert RST */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+    udelay (40);
+    /* reset NCR registers */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+    NCR5380_write( MODE_REG, MR_BASE );
+    NCR5380_write( TARGET_COMMAND_REG, 0 );
+    NCR5380_write( SELECT_ENABLE_REG, 0 );
+    /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+     * through anymore ... */
+    (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+      /* XXX see below                                            XXX */
+
+    /* MSch: old-style reset: actually abort all command processing here */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; to avoid problems with re-inserting the commands
+     * into the issue_queue (via scsi_done()), the aborted commands are
+     * remembered in local variables first.
+     */
+    save_flags(flags);
+    cli();
+    connected = (Scsi_Cmnd *)hostdata->connected;
+    hostdata->connected = NULL;
+    disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    restore_flags(flags);
+
+    /* In order to tell the mid-level code which commands were aborted, 
+     * set the command status to DID_RESET and call scsi_done() !!!
+     * This ultimately aborts processing of these commands in the mid-level.
+     */
+
+    if ((cmd = connected)) {
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+
+    for (i = 0; (cmd = disconnected_queue); ++i) {
+	disconnected_queue = NEXT(cmd);
+	NEXT(cmd) = NULL;
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+    if (i > 0)
+	ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+
+    /* since all commands have been explicitly terminated, we need to tell
+     * the midlevel code that the reset was SUCCESSFUL, and there is no 
+     * need to 'wake up' the commands by a request_sense
+     */
+    return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+#else /* 1 */
+
+    /* MSch: new-style reset handling: let the mid-level do what it can */
+
+    /* ++guenther: MID-LEVEL IS STILL BROKEN.
+     * Mid-level is supposed to requeue all commands that were active on the
+     * various low-level queues. In fact it does this, but that's not enough
+     * because all these commands are subject to timeout. And if a timeout
+     * happens for any removed command, *_abort() is called but all queues
+     * are now empty. Abort then gives up the falcon lock, which is fatal,
+     * since the mid-level will queue more commands and must have the lock
+     * (it's all happening inside timer interrupt handler!!).
+     * Even worse, abort will return NOT_RUNNING for all those commands not
+     * on any queue, so they won't be retried ...
+     *
+     * Conclusion: either scsi.c disables timeout for all resetted commands
+     * immediately, or we loose!  As of linux-2.0.20 it doesn't.
+     */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; so clear the low-level status here to avoid 
+     * conflicts when the mid-level code tries to wake up the affected 
+     * commands!
+     */
+
+    if (hostdata->issue_queue)
+	ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+    if (hostdata->connected) 
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+    if (hostdata->disconnected_queue)
+	ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+    save_flags(flags);
+    cli();
+    hostdata->issue_queue = NULL;
+    hostdata->connected = NULL;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    restore_flags(flags);
+
+    /* we did no complete reset of all commands, so a wakeup is required */
+    return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+#endif /* 1 */
+}
+
+/* Local Variables: */
+/* tab-width: 8     */
+/* End:             */
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/sun3_scsi.c linux/drivers/scsi/sun3_scsi.c
--- v2.3.44/linux/drivers/scsi/sun3_scsi.c	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/sun3_scsi.c	Sun Feb 13 11:21:42 2000
@@ -1,6 +1,8 @@
 /*
  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
  *
+ * Sun3 DMA routines added by Sam Creasey (sammy@oh.verio.com)
+ *
  * Adapted from mac_scsinew.c:
  */
 /*
@@ -44,13 +46,10 @@
  */
 
 /*
- * $Log: mac_NCR5380.c,v $
+ * $Log: sun3_NCR5380.c,v $
  */
 
 #define AUTOSENSE
-#if 0
-#define PSEUDO_DMA
-#endif
 
 #include <linux/types.h>
 #include <linux/stddef.h>
@@ -68,6 +67,9 @@
 #include <asm/system.h>
 
 #include <asm/sun3ints.h>
+#include <asm/dvma.h>
+/* dma on! */
+#define REAL_DMA
 
 #include "scsi.h"
 #include "hosts.h"
@@ -75,17 +77,12 @@
 #include "NCR5380.h"
 #include "constants.h"
 
-#if 0
-#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION)
-#define NCR_TIMEOUT 100
-#else
-#define NDEBUG (NDEBUG_ABORT)
-#endif
-
 #define USE_WRAPPER
 #define RESET_BOOT
 #define DRIVER_SETUP
 
+#define NDEBUG 0
+
 /*
  * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
  */
@@ -94,14 +91,14 @@
 #undef DRIVER_SETUP
 #endif
 
-#define	ENABLE_IRQ()	sun3_enable_irq( IRQ_SUN3_SCSI ); 
-#define	DISABLE_IRQ()	sun3_enable_irq( IRQ_SUN3_SCSI );
+#undef SUPPORT_TAGS
+
+#define	ENABLE_IRQ()	enable_irq( IRQ_SUN3_SCSI ); 
 
-/* extern void via_scsi_clear(void); */
 
 static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
-static char sun3scsi_read(struct Scsi_Host *instance, int reg);
-static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value);
+static inline unsigned char sun3scsi_read(int reg);
+static inline void sun3scsi_write(int reg, int value);
 
 static int setup_can_queue = -1;
 static int setup_cmd_per_lun = -1;
@@ -111,38 +108,65 @@
 #endif
 static int setup_hostid = -1;
 
-static int polled_scsi_on = 0;
+static Scsi_Cmnd *sun3_dma_setup_done = NULL;
 
 #define	AFTER_RESET_DELAY	(HZ/2)
 
-static volatile unsigned char *sun3_scsi_regp = IOBASE_SUN3_SCSI;
-/*
-static volatile unsigned char *sun3_scsi_drq  = NULL;
-static volatile unsigned char *sun3_scsi_nodrq = NULL;
-*/
+/* ms to wait after hitting dma regs */
+#define SUN3_DMA_DELAY 5
+
+/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
+#define SUN3_DVMA_BUFSIZE 0xe000
+
+/* minimum number of bytes to to dma on */
+#define SUN3_DMA_MINSIZE 128
+
+static struct proc_dir_entry proc_scsi_sun3_5380 = {
+	PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2
+};
+
+static volatile unsigned char *sun3_scsi_regp;
+static volatile struct sun3_dma_regs *dregs;
+static unsigned char *dmabuf = NULL; /* dma memory buffer */
+static struct sun3_udc_regs *udc_regs = NULL;
+static void *sun3_dma_orig_addr = NULL;
+static unsigned long sun3_dma_orig_count = 0;
+static int sun3_dma_active = 0;
 
 /*
- * Function : sun3_scsi_setup(char *str, int *ints)
- *
- * Purpose : booter command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
- *
- * TODO: make it actually work!
- *
+ * NCR 5380 register access functions
  */
 
-void sun3_scsi_setup(char *str, int *ints) {
-	printk("sun3_scsi_setup() called\n");
-	setup_can_queue = -1;
-	setup_cmd_per_lun = -1;
-	setup_sg_tablesize = -1;
-	setup_hostid = -1;
-#ifdef SUPPORT_TAGS
-	setup_use_tagged_queuing = -1;
-#endif
-	printk("sun3_scsi_setup() done\n");
+static inline unsigned char sun3scsi_read(int reg)
+{
+	return( sun3_scsi_regp[reg] );
+}
+
+static inline void sun3scsi_write(int reg, int value)
+{
+	sun3_scsi_regp[reg] = value;
+}
+
+/* dma controller register access functions */
+
+static inline unsigned short sun3_udc_read(unsigned char reg)
+{
+	unsigned short ret;
+
+	dregs->udc_addr = UDC_CSR;
+	udelay(SUN3_DMA_DELAY);
+	ret = dregs->udc_data;
+	udelay(SUN3_DMA_DELAY);
+	
+	return ret;
+}
+
+static inline void sun3_udc_write(unsigned short val, unsigned char reg)
+{
+	dregs->udc_addr = reg;
+	udelay(SUN3_DMA_DELAY);
+	dregs->udc_data = val;
+	udelay(SUN3_DMA_DELAY);
 }
 
 /*
@@ -165,7 +189,6 @@
 int sun3scsi_detect(Scsi_Host_Template * tpnt)
 {
 	unsigned long ioaddr, iopte;
-	unsigned short *ioptr;
 	int count = 0;
 	static int called = 0;
 	struct Scsi_Host *instance;
@@ -173,9 +196,7 @@
 	if(called)
 		return 0;
 
-printk("sun3scsi_detect(0x%p)\n",tpnt);
-
-	tpnt->proc_name = "Sun3 5380 SCSI"; /* Could you spell "ewww..."? */
+	tpnt->proc_dir = &proc_scsi_sun3_5380;
 
 	/* setup variables */
 	tpnt->can_queue =
@@ -204,7 +225,6 @@
                 if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
                    IOBASE_SUN3_SCSI) {
                         count = 1;
-printk("Found ioaddr in pmeg\n");
                         break;
                 }
         }
@@ -214,22 +234,19 @@
 		return 0;
 	}
 
-	sun3_scsi_regp = ioaddr;
+	sun3_scsi_regp = (unsigned char *)ioaddr;
+	dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
+
+	if((dmabuf = sun3_dvma_malloc(SUN3_DVMA_BUFSIZE)) == NULL) {
+	     printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+	     return 0;
+	}
 
-	/* doing some stuff like resetting DVMA: */
-	ioptr = ioaddr;
-        *(ioptr+8) = 0;
-	udelay(10);
-        *(ioptr+9) = 0;
-	udelay(10);
-        *(ioptr+12) = 0;
-	udelay(10);
-        *(ioptr+12) = 0x7;
-	udelay(10);
-	printk("SCSI status reg = %x\n", *(ioptr+12));
-	udelay(10);
-        *(ioptr+13) = 0;
-	udelay(10);
+	if((udc_regs = sun3_dvma_malloc(sizeof(struct sun3_udc_regs)))
+	   == NULL) {
+	     printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+	     return 0;
+	}
 
 #ifdef SUPPORT_TAGS
 	if (setup_use_tagged_queuing < 0)
@@ -239,18 +256,6 @@
 	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
 	default_instance = instance;
 
-/*
-	if (macintosh_config->ident == MAC_MODEL_IIFX) {
-		mac_scsi_regp  = via1_regp+0x8000;
-		mac_scsi_drq   = via1_regp+0x6000;
-		mac_scsi_nodrq = via1_regp+0x12000;
-	} else {
-		mac_scsi_regp  = via1_regp+0x10000;
-		mac_scsi_drq   = via1_regp+0x6000;
-		mac_scsi_nodrq = via1_regp+0x12000;
-	}
-*/
-
         instance->io_port = (unsigned long) ioaddr;
 	instance->irq = IRQ_SUN3_SCSI;
 
@@ -260,15 +265,20 @@
 
         ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
 
-	if (instance->irq != IRQ_NONE)
-		if (sun3_request_irq(instance->irq, sun3scsi_intr,
-		                0, "Sun3SCSI-5380", NULL)) {
-			printk("scsi%d: IRQ%d not free, interrupts disabled\n",
-			       instance->host_no, instance->irq);
-			instance->irq = IRQ_NONE;
-		}
-
-	printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
+	if (request_irq(instance->irq, scsi_sun3_intr,
+			     0, "Sun3SCSI-5380", NULL)) {
+#ifndef REAL_DMA
+		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+		       instance->host_no, instance->irq);
+		instance->irq = IRQ_NONE;
+#else
+		printk("scsi%d: IRQ%d not free, bailing out\n",
+		       instance->host_no, instance->irq);
+		return 0;
+#endif
+	}
+	
+	printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
 	if (instance->irq == IRQ_NONE)
 		printk ("s disabled");
 	else
@@ -280,6 +290,12 @@
 	NCR5380_print_options(instance);
 	printk("\n");
 
+	dregs->csr = 0;
+	udelay(SUN3_DMA_DELAY);
+	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+	udelay(SUN3_DMA_DELAY);
+	dregs->fifo_count = 0;
+
 	called = 1;
 	return 1;
 }
@@ -342,34 +358,34 @@
     return "";
 }
 
+// safe bits for the CSR
+#define CSR_GOOD 0x060f
 
-/*
- * NCR 5380 register access functions
- */
-
-static char sun3scsi_read(struct Scsi_Host *instance, int reg)
+static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
 {
-/*
-printk("sun3scsi_read(instance=0x%p, reg=0x%x): @0x%p= %d\n",instance,reg,sun3_scsi_regp,sun3_scsi_regp[reg]);
-*/
-	return( sun3_scsi_regp[reg] );
-}
+	unsigned short csr = dregs->csr;
 
-static void sun3scsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-/*
-	printk("sun3scsi_write(instance=0x%p, reg=0x%x, value=0x%x)\n", instance, reg, value);
-*/
-	sun3_scsi_regp[reg] = value;
-}
+	if(csr & ~CSR_GOOD) {
+		if(csr & CSR_DMA_BUSERR) {
+			printk("scsi%d: bus error in dma\n", default_instance->host_no);
+		}
+
+		if(csr & CSR_DMA_CONFLICT) {
+			printk("scsi%d: dma conflict\n", default_instance->host_no);
+		}
+	}
 
-#include "NCR5380.c"
+	if(csr & (CSR_SDB_INT | CSR_DMA_INT))
+		NCR5380_intr(irq, dummy, fp);
+}
 
 /*
  * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
  * reentering NCR5380_print_status seems to have ugly side effects
  */
 
+/* this doesn't seem to get used at all -- sam */
+#if 0
 void sun3_sun3_debug (void)
 {
 	unsigned long flags;
@@ -381,32 +397,141 @@
 			NCR5380_print_status(default_instance);
 			restore_flags(flags);
 	}
-#if 0
-	polled_scsi_on = 1;
-#endif
 }
-/*
- * Helper function for interrupt trouble. More ugly side effects here.
- */
+#endif
 
-void scsi_sun3_polled (void)
+
+/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
+static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
 {
-	unsigned long flags;
-	NCR5380_local_declare();
-	struct Scsi_Host *instance;
+	if(write_flag) 
+		memcpy(dmabuf, data, count);
+	else {
+		sun3_dma_orig_addr = data;
+		sun3_dma_orig_count = count;
+	}
+
+	dregs->fifo_count = 0;
+	sun3_udc_write(UDC_RESET, UDC_CSR);
 	
-	instance = default_instance;
-	NCR5380_setup(instance);
-	if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
-	{
-		printk("SCSI poll\n");
-		save_flags(flags);
-		cli();
-		sun3scsi_intr(IRQ_SUN3_SCSI, instance, NULL);
-		restore_flags(flags);
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+	
+	/* set direction */
+	if(write_flag)
+		dregs->csr |= CSR_SEND;
+	else
+		dregs->csr &= ~CSR_SEND;
+	
+	/* byte count for fifo */
+	dregs->fifo_count = count;
+
+	sun3_udc_write(UDC_RESET, UDC_CSR);
+	
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+	
+
+	if(dregs->fifo_count != count) { 
+		printk("scsi%d: fifo_mismatch %04x not %04x\n",
+		       default_instance->host_no, dregs->fifo_count,
+		       (unsigned int) count);
+		NCR5380_print(default_instance);
+	}
+
+	/* setup udc */
+	udc_regs->addr_hi = ((sun3_dvma_vtop(dmabuf) & 0xff0000) >> 8);
+	udc_regs->addr_lo = (sun3_dvma_vtop(dmabuf) & 0xffff);
+	udc_regs->count = count/2; /* count in words */
+	udc_regs->mode_hi = UDC_MODE_HIWORD;
+	if(write_flag) {
+		if(count & 1)
+			udc_regs->count++;
+		udc_regs->mode_lo = UDC_MODE_LSEND;
+		udc_regs->rsel = UDC_RSEL_SEND;
+	} else {
+		udc_regs->mode_lo = UDC_MODE_LRECV;
+		udc_regs->rsel = UDC_RSEL_RECV;
 	}
+	
+	/* announce location of regs block */
+	sun3_udc_write(((sun3_dvma_vtop(udc_regs) & 0xff0000) >> 8),
+		       UDC_CHN_HI); 
+
+	sun3_udc_write((sun3_dvma_vtop(udc_regs) & 0xffff), UDC_CHN_LO);
+
+	/* set dma master on */
+	sun3_udc_write(0xd, UDC_MODE);
+
+	/* interrupt enable */
+	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
+	
+       	return count;
+
 }
 
+static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+{
+	unsigned short resid;
+
+	dregs->udc_addr = 0x32; 
+	udelay(SUN3_DMA_DELAY);
+	resid = dregs->udc_data;
+	udelay(SUN3_DMA_DELAY);
+	resid *= 2;
+
+	return (unsigned long) resid;
+}
+
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+				    int write_flag)
+{
+		return wanted;
+}
+
+/* clean up after our dma is done */
+static int sun3scsi_dma_finish(void)
+{
+	unsigned short count;
+	int ret = 0;
+	
+	count = sun3scsi_dma_residual(default_instance);
+
+	sun3_dma_active = 0;
+
+	/* if we've finished a read, copy out the data we read */
+ 	if(sun3_dma_orig_addr) {
+		/* check for residual bytes after dma end */
+		if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
+			     (BASR_PHASE_MATCH | BASR_ACK))) {
+			printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
+			printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
+			ret = count;
+		}
+		
+		/* copy in what we dma'd no matter what */
+		memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
+		sun3_dma_orig_addr = NULL;
+
+	}
+	
+	sun3_udc_write(UDC_RESET, UDC_CSR);
+	
+	dregs->csr &= ~CSR_SEND;
+
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+	
+	sun3_dma_setup_done = NULL;
+
+	return ret;
+
+}
+	
+#include "sun3_NCR5380.c"
 
 #ifdef MODULE
 
@@ -414,3 +539,4 @@
 
 #include "scsi_module.c"
 #endif
+
diff -u --recursive --new-file v2.3.44/linux/drivers/scsi/sun3_scsi.h linux/drivers/scsi/sun3_scsi.h
--- v2.3.44/linux/drivers/scsi/sun3_scsi.h	Thu Nov 11 20:11:48 1999
+++ linux/drivers/scsi/sun3_scsi.h	Sun Feb 13 11:21:42 2000
@@ -1,6 +1,8 @@
 /*
  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
  *
+ * Sun3 DMA additions by Sam Creasey (sammy@oh.verio.com)
+ *
  * Adapted from mac_scsinew.h:
  */
 /*
@@ -102,17 +104,271 @@
 #define NCR5380_setup(instance) \
         _instance = instance
 
-#define NCR5380_read(reg) sun3scsi_read(_instance, reg)
-#define NCR5380_write(reg, value) sun3scsi_write(_instance, reg, value)
+#define NCR5380_read(reg) sun3scsi_read(reg)
+#define NCR5380_write(reg, value) sun3scsi_write(reg, value)
 
 #define NCR5380_intr sun3scsi_intr
 #define NCR5380_queue_command sun3scsi_queue_command
-#define NCR5380_abort sun3scsi_abort
 #define NCR5380_reset sun3scsi_reset
+#define NCR5380_abort sun3scsi_abort
 #define NCR5380_proc_info sun3scsi_proc_info
+#define NCR5380_dma_xfer_len(i, cmd, phase) \
+        sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
+#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1)
+#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0)
+#define NCR5380_dma_residual sun3scsi_dma_residual
 
 #define BOARD_NORMAL	0
 #define BOARD_NCR53C400	1
+
+/* additional registers - mainly DMA control regs */
+/* these start at regbase + 8 -- directly after the NCR regs */
+struct sun3_dma_regs {
+	unsigned short vmeregs[4];  /* unimpl vme stuff */
+	unsigned short udc_data; /* udc dma data reg */
+	unsigned short udc_addr; /* uda dma addr reg */
+	unsigned short fifo_data; /* fifo data reg, holds extra byte on
+				     odd dma reads */
+	unsigned short fifo_count; 
+	unsigned short csr; /* control/status reg */
+};
+
+/* ucd chip specific regs - live in dvma space */
+struct sun3_udc_regs {
+     unsigned short rsel; /* select regs to load */
+     unsigned short addr_hi; /* high word of addr */
+     unsigned short addr_lo; /* low word */
+     unsigned short count; /* words to be xfer'd */
+     unsigned short mode_hi; /* high word of channel mode */
+     unsigned short mode_lo; /* low word of channel mode */
+};
+
+/* addresses of the udc registers */
+#define UDC_MODE 0x38 
+#define UDC_CSR 0x2e /* command/status */
+#define UDC_CHN_HI 0x26 /* chain high word */
+#define UDC_CHN_LO 0x22 /* chain lo word */
+#define UDC_CURA_HI 0x1a /* cur reg A high */
+#define UDC_CURA_LO 0x0a /* cur reg A low */
+#define UDC_CURB_HI 0x12 /* cur reg B high */
+#define UDC_CURB_LO 0x02 /* cur reg B low */
+#define UDC_MODE_HI 0x56 /* mode reg high */
+#define UDC_MODE_LO 0x52 /* mode reg low */
+#define UDC_COUNT 0x32 /* words to xfer */
+
+/* some udc commands */
+#define UDC_RESET 0
+#define UDC_CHN_START 0xa0 /* start chain */
+#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
+
+/* udc mode words */
+#define UDC_MODE_HIWORD 0x40
+#define UDC_MODE_LSEND 0xc2
+#define UDC_MODE_LRECV 0xd2
+
+/* udc reg selections */
+#define UDC_RSEL_SEND 0x282
+#define UDC_RSEL_RECV 0x182
+
+/* bits in csr reg */
+#define CSR_DMA_ACTIVE 0x8000
+#define CSR_DMA_CONFLICT 0x4000
+#define CSR_DMA_BUSERR 0x2000
+
+#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
+#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
+#define CSR_DMA_INT 0x100 /* dma interrupt pending */
+
+#define CSR_SEND 0x8 /* 1 = send  0 = recv */
+#define CSR_FIFO 0x2 /* reset fifo */
+#define CSR_INTR 0x4 /* interrupt enable */
+#define CSR_SCSI 0x1 
+
+// debugging printk's, taken from atari_scsi.h 
+/* Debugging printk definitions:
+ *
+ *  ARB  -> arbitration
+ *  ASEN -> auto-sense
+ *  DMA  -> DMA
+ *  HSH  -> PIO handshake
+ *  INF  -> information transfer
+ *  INI  -> initialization
+ *  INT  -> interrupt
+ *  LNK  -> linked commands
+ *  MAIN -> NCR5380_main() control flow
+ *  NDAT -> no data-out phase
+ *  NWR  -> no write commands
+ *  PIO  -> PIO transfers
+ *  PDMA -> pseudo DMA (unused on Atari)
+ *  QU   -> queues
+ *  RSL  -> reselections
+ *  SEL  -> selections
+ *  USL  -> usleep cpde (unused on Atari)
+ *  LBS  -> last byte sent (unused on Atari)
+ *  RSS  -> restarting of selections
+ *  EXT  -> extended messages
+ *  ABRT -> aborting and resetting
+ *  TAG  -> queue tag handling
+ *  MER  -> merging of consec. buffers
+ *
+ */
+
+
+
+#if NDEBUG & NDEBUG_ARBITRATION
+#define ARB_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ARB_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_AUTOSENSE
+#define ASEN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ASEN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_DMA
+#define DMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define DMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_HANDSHAKE
+#define HSH_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define HSH_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INFORMATION
+#define INF_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INF_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INIT
+#define INI_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INI_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INTR
+#define INT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LINKED
+#define LNK_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LNK_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MAIN
+#define MAIN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MAIN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_DATAOUT
+#define NDAT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NDAT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_WRITE
+#define NWR_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NWR_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PIO
+#define PIO_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PIO_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PSEUDO_DMA
+#define PDMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PDMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_QUEUES
+#define QU_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define QU_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESELECTION
+#define RSL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_SELECTION
+#define SEL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define SEL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_USLEEP
+#define USL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define USL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+#define LBS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LBS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESTART_SELECT
+#define RSS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_EXTENDED
+#define EXT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define EXT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_ABORT
+#define ABRT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ABRT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_TAGS
+#define TAG_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define TAG_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MERGING
+#define MER_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MER_PRINTK(format, args...)
+#endif
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask)	\
+	((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+#define NDEBUG_ANY	0xffffffff
+
+
 
 #endif /* ndef HOSTS_C */
 #endif /* SUN3_NCR5380_H */
diff -u --recursive --new-file v2.3.44/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- v2.3.44/linux/drivers/sound/ac97_codec.c	Tue Feb  1 01:35:44 2000
+++ linux/drivers/sound/ac97_codec.c	Sun Feb 13 18:50:12 2000
@@ -19,9 +19,11 @@
  *	along with this program; if not, write to the Free Software
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  History
- *	Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
- *	Isloated from trident.c to support multiple ac97 codec
+ * History
+ * v0.2 Feb 10 2000 Ollie Lho
+ *	add ac97_read_proc for /proc/driver/vnedor/ac97
+ * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
+ *	Isolated from trident.c to support multiple ac97 codec
  */
 #include <linux/module.h>
 #include <linux/version.h>
@@ -40,7 +42,7 @@
 	unsigned int id;
 	char *name;
 	int  (*init)  (struct ac97_codec *codec);
-} snd_ac97_codec_ids[] = {
+} ac97_codec_ids[] = {
 	{0x414B4D00, "Asahi Kasei AK4540"     , NULL},
 	{0x41445340, "Analog Devices AD1881"  , NULL},
 	{0x43525900, "Cirrus Logic CS4297"    , NULL},
@@ -52,9 +54,46 @@
 	{0x83847605, "SigmaTel STAC9704"      , NULL},
 	{0x83847608, "SigmaTel STAC9708"      , NULL},
 	{0x83847609, "SigmaTel STAC9721/23"   , NULL},
+	{0x54524108, "TriTech TR28028"        , NULL},
+	{0x574D4C00, "Wolfson WM9704"         , NULL},
 	{0x00000000, NULL, NULL}
 };
 
+static const char *ac97_stereo_enhancements[] =
+{
+	/*   0 */ "No 3D Stereo Enhancement",
+	/*   1 */ "Analog Devices Phat Stereo",
+	/*   2 */ "Creative Stereo Enhancement",
+	/*   3 */ "National Semi 3D Stereo Enhancement",
+	/*   4 */ "YAMAHA Ymersion",
+	/*   5 */ "BBE 3D Stereo Enhancement",
+	/*   6 */ "Crystal Semi 3D Stereo Enhancement",
+	/*   7 */ "Qsound QXpander",
+	/*   8 */ "Spatializer 3D Stereo Enhancement",
+	/*   9 */ "SRS 3D Stereo Enhancement",
+	/*  10 */ "Platform Tech 3D Stereo Enhancement",
+	/*  11 */ "AKM 3D Audio",
+	/*  12 */ "Aureal Stereo Enhancement",
+	/*  13 */ "Aztech 3D Enhancement",
+	/*  14 */ "Binaura 3D Audio Enhancement",
+	/*  15 */ "ESS Technology Stereo Enhancement",
+	/*  16 */ "Harman International VMAx",
+	/*  17 */ "Nvidea 3D Stereo Enhancement",
+	/*  18 */ "Philips Incredible Sound",
+	/*  19 */ "Texas Instruments 3D Stereo Enhancement",
+	/*  20 */ "VLSI Technology 3D Stereo Enhancement",
+	/*  21 */ "TriTech 3D Stereo Enhancement",
+	/*  22 */ "Realtek 3D Stereo Enhancement",
+	/*  23 */ "Samsung 3D Stereo Enhancement",
+	/*  24 */ "Wolfson Microelectronics 3D Enhancement",
+	/*  25 */ "Delta Integration 3D Enhancement",
+	/*  26 */ "SigmaTel 3D Enhancement",
+	/*  27 */ "Reserved 27",
+	/*  28 */ "Rockwell 3D Stereo Enhancement",
+	/*  29 */ "Reserved 29",
+	/*  30 */ "Reserved 30",
+	/*  31 */ "Reserved 31"
+};
 
 /* this table has default mixer values for all OSS mixers. */
 static struct mixer_defaults {
@@ -86,9 +125,9 @@
 } ac97_hw[SOUND_MIXER_NRDEVICES]= {
 	[SOUND_MIXER_VOLUME]	=	{AC97_MASTER_VOL_STEREO,63},
 	[SOUND_MIXER_BASS]	=	{AC97_MASTER_TONE,	15},
-	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE, 	15},
+	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE,	15},
 	[SOUND_MIXER_PCM]	=	{AC97_PCMOUT_VOL,	31},
-	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,  	15},
+	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,	15},
 	[SOUND_MIXER_LINE]	=	{AC97_LINEIN_VOL,	31},
 	[SOUND_MIXER_MIC]	=	{AC97_MIC_VOL,		31},
 	[SOUND_MIXER_CD]	=	{AC97_CD_VOL,		31},
@@ -155,10 +194,13 @@
 			right = 100 - ((right * 100) / mh->scale);
 			left = 100 - ((left * 100) / mh->scale);
 		}
-
 		ret = left | (right << 8);
 	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
 		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
+		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
+		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
 	} else if (oss_channel == SOUND_MIXER_MIC) {
 		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
 		/*  the low bit is optional in the tone sliders and masking
@@ -200,10 +242,14 @@
 		} else {
 			right = ((100 - right) * mh->scale) / 100;
 			left = ((100 - left) * mh->scale) / 100;
-		}
+		}			
 		val = (left << 8) | right;
 	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
 		val = (((100 - left) * mh->scale) / 100) << 1;
+	} else if (oss_channel == SOUND_MIXER_PHONEIN) {
+		val = (((100 - left) * mh->scale) / 100);
+	} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
+		val = (((100 - left) * mh->scale) / 100);
 	} else if (oss_channel == SOUND_MIXER_MIC) {
 		val = codec->codec_read(codec , mh->offset) & ~0x801f;
 		val |= (((100 - left) * mh->scale) / 100);
@@ -212,11 +258,10 @@
 	} else if (oss_channel == SOUND_MIXER_BASS) {
 		val = codec->codec_read(codec , mh->offset) & ~0x0f00;
 		val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
-	} else if (oss_channel == SOUND_MIXER_TREBLE)	 {
+	} else if (oss_channel == SOUND_MIXER_TREBLE) {
 		val = codec->codec_read(codec , mh->offset) & ~0x000f;
 		val |= (((100 - left) * mh->scale) / 100) & 0x000e;
 	}
-
 #ifdef DEBUG
 	printk(" 0x%04x", val);
 #endif
@@ -335,11 +380,11 @@
 				return -EINVAL;
 
 			/* do we ever want to touch the hardware? */
-			/* val = codec->read_mixer(card,i); */
-			val = codec->mixer_state[i];
+			val = codec->read_mixer(card, i);
+			/* val = codec->mixer_state[i]; */
 			break;
 		}
-		return put_user(val,(int *)arg);
+		return put_user(val, (int *)arg);
 	}
 
 	if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
@@ -368,6 +413,76 @@
 	return -EINVAL;
 }
 
+/* entry point for /proc/driver/controller_vendor/ac97/%d */
+int ac97_read_proc (char *page, char **start, off_t off,
+		    int count, int *eof, void *data)
+{
+	int len = 0, cap, extid, val, id1, id2;
+	struct ac97_codec *codec;
+
+	if ((codec = data) == NULL)
+		return -ENODEV;
+
+	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
+	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+	len += sprintf (page+len, "Vendor name      : %s\n", codec->name);
+	len += sprintf (page+len, "Vendor id        : %04X %04X\n", id1, id2);
+
+	extid = codec->codec_read(codec, AC97_EXTENDED_ID);
+	extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
+	len += sprintf (page+len, "AC97 Version     : %s\n",
+			extid ? "2.0 or later" : "1.0");
+
+	cap = codec->codec_read(codec, AC97_RESET);
+	len += sprintf (page+len, "Capabilities     :%s%s%s%s%s%s\n",
+			cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
+			cap & 0x0002 ? " -reserved1-" : "",
+			cap & 0x0004 ? " -bass & treble-" : "",
+			cap & 0x0008 ? " -simulated stereo-" : "",
+			cap & 0x0010 ? " -headphone out-" : "",
+			cap & 0x0020 ? " -loudness-" : "");
+	val = cap & 0x00c0;
+	len += sprintf (page+len, "DAC resolutions  :%s%s%s\n",
+			" -16-bit-",
+			val & 0x0040 ? " -18-bit-" : "",
+			val & 0x0080 ? " -20-bit-" : "");
+	val = cap & 0x0300;
+	len += sprintf (page+len, "ADC resolutions  :%s%s%s\n",
+			" -16-bit-",
+			val & 0x0100 ? " -18-bit-" : "",
+			val & 0x0200 ? " -20-bit-" : "");
+	len += sprintf (page+len, "3D enhancement   : %s\n",
+			ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
+
+	val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
+	len += sprintf (page+len, "POP path         : %s 3D\n"
+			"Sim. stereo      : %s\n"
+			"3D enhancement   : %s\n"
+			"Loudness         : %s\n"
+			"Mono output      : %s\n"
+			"MIC select       : %s\n"
+			"ADC/DAC loopback : %s\n",
+			val & 0x8000 ? "post" : "pre",
+			val & 0x4000 ? "on" : "off",
+			val & 0x2000 ? "on" : "off",
+			val & 0x1000 ? "on" : "off",
+			val & 0x0200 ? "MIC" : "MIX",
+			val & 0x0100 ? "MIC2" : "MIC1",
+			val & 0x0080 ? "on" : "off");
+
+	cap = extid;
+	len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
+			cap & 0x0001 ? " -var rate PCM audio-" : "",
+			cap & 0x0002 ? " -2x PCM audio out-" : "",
+			cap & 0x0008 ? " -var rate MIC in-" : "",
+			cap & 0x0040 ? " -PCM center DAC-" : "",
+			cap & 0x0080 ? " -PCM surround DAC-" : "",
+			cap & 0x0100 ? " -PCM LFE DAC-" : "",
+			cap & 0x0200 ? " -slot/DAC mappings-" : "");
+
+	return len;
+}
+
 int ac97_probe_codec(struct ac97_codec *codec)
 {
 	u16 id1, id2, cap;
@@ -381,10 +496,10 @@
 	
 	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
 	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
-	for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
-		if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
-			codec->name = snd_ac97_codec_ids[i].name;
-			codec->codec_init = snd_ac97_codec_ids[i].init;
+	for (i = 0, codec->name = NULL; i < arraysize (ac97_codec_ids[i]); i++) {
+		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+			codec->name = ac97_codec_ids[i].name;
+			codec->codec_init = ac97_codec_ids[i].init;
 			break;
 		}
 	}
@@ -392,7 +507,6 @@
 		codec->name = "Unknown";
 	printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
 	       id1, id2, codec->name);
-	printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap);
 
 	/* mixer masks */
 	codec->supported_mixers = AC97_SUPPORTED_MASK;
@@ -437,4 +551,5 @@
 	return 1;
 }
 
+EXPORT_SYMBOL(ac97_read_proc);
 EXPORT_SYMBOL(ac97_probe_codec);
diff -u --recursive --new-file v2.3.44/linux/drivers/sound/ac97_codec.h linux/drivers/sound/ac97_codec.h
--- v2.3.44/linux/drivers/sound/ac97_codec.h	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/ac97_codec.h	Sun Feb 13 18:49:08 2000
@@ -116,7 +116,8 @@
 	SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT)
 
 #define AC97_RECORD_MASK (SOUND_MASK_MIC|\
-	SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+	SOUND_MASK_CD|SOUND_MASK_VIDEO|\
+	SOUND_MASK_LINE1| SOUND_MASK_LINE|\
 	SOUND_MASK_PHONEIN)
 
 #define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
@@ -153,6 +154,8 @@
 	unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
 };
 
+extern int ac97_read_proc (char *page_out, char **start, off_t off,
+			   int count, int *eof, void *data);
 extern int ac97_probe_codec(struct ac97_codec *);
 
 #endif /* _AC97_CODEC_H_ */
diff -u --recursive --new-file v2.3.44/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.3.44/linux/drivers/sound/dmasound.c	Thu Feb 10 17:11:14 2000
+++ linux/drivers/sound/dmasound.c	Sun Feb 13 10:47:01 2000
@@ -116,6 +116,7 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
+#include <asm/feature.h>
 #include "awacs_defs.h"
 #include <linux/nvram.h>
 #include <linux/vt_kern.h>
@@ -178,6 +179,7 @@
 static int awacs_rate_index;
 static int awacs_subframe;
 static int awacs_spkr_vol;
+static struct device_node* awacs_node;
 
 static int awacs_revision;
 #define AWACS_BURGUNDY	100		/* fake revision # for burgundy */
@@ -898,7 +900,7 @@
 
 
 void dmasound_init(void);
-void dmasound_setup(char *str, int *ints);
+static int dmasound_setup(char *str);
 
 
 /*** Translations ************************************************************/
@@ -3208,9 +3210,15 @@
 	out_le32(&awacs_txdma->control, RUN<<16);
 	/* disable interrupts from awacs interface */
 	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-	free_irq(awacs_irq, pmac_awacs_intr);
-	free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
-	free_irq(awacs_rx_irq, pmac_awacs_rx_intr);
+#ifdef CONFIG_PMAC_PBOOK
+	if (is_pbook_G3) {
+		feature_clear(awacs_node, FEATURE_Sound_power);
+		feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+	}
+#endif
+	free_irq(awacs_irq, 0);
+	free_irq(awacs_tx_irq, 0);
+	free_irq(awacs_rx_irq, 0);
 	kfree(awacs_tx_cmd_space);
 	if (awacs_rx_cmd_space)
 		kfree(awacs_rx_cmd_space);
@@ -3281,12 +3289,10 @@
 	/* We really want to execute a DMA stop command, after the AWACS
 	 * is initialized.
 	 * For reasons I don't understand, it stops the hissing noise
-	 * common to many PowerBook G3 systems (like mine :-).  Maybe it
-	 * is just the AWACS control register change......
+	 * common to many PowerBook G3 systems (like mine :-).
 	 */
 	out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
 	st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-	out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00));
 	out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
 	out_le32(&awacs_txdma->control, RUN | (RUN << 16));
 
@@ -3544,6 +3550,11 @@
 	save_flags(flags); cli();
 	if (beep_playing) {
 		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+		out_le32(&awacs->control,
+			 (in_le32(&awacs->control) & ~0x1f00)
+			 | (awacs_rate_index << 8));
+		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
 		beep_playing = 0;
 	}
 	restore_flags(flags);
@@ -3645,8 +3656,23 @@
 		PMacSilence();
 		disable_irq(awacs_irq);
 		disable_irq(awacs_tx_irq);
+		if (is_pbook_G3) {
+			feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+			feature_clear(awacs_node, FEATURE_Sound_power);
+		}
 		break;
 	case PBOOK_WAKE:
+		/* There is still a problem on wake. Sound seems to work fine
+		   if I launch mpg123 and resumes fine if mpg123 was playing,
+		   but the console beep is dead until I do something with the
+		   mixer. Probably yet another timing issue */
+		if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+		    || !feature_test(awacs_node, FEATURE_Sound_power)) {
+			/* these aren't present on the 3400 AFAIK -- paulus */
+			feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+			feature_set(awacs_node, FEATURE_Sound_power);
+			mdelay(1000);
+		}
 		out_le32(&awacs->control, MASK_IEPC
 			 | (awacs_rate_index << 8) | 0x11
 			 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
@@ -3663,6 +3689,16 @@
 			mdelay(2);
 			awacs_write(awacs_reg[1] | MASK_ADDR1);
 		}
+		/* enable CD sound input */
+		if (macio_base && is_pbook_G3) {
+			out_8(macio_base + 0x37, 3);
+		} else if (is_pbook_3400) {
+			feature_set(awacs_node, FEATURE_IOBUS_enable);
+			udelay(10);
+			in_8((unsigned char *)0xf301a190);
+		}
+ 		/* Resume pending sounds. */
+ 		PMacPlay();
 	}
 	return PBOOK_SLEEP_OK;
 }
@@ -5139,6 +5175,7 @@
 	u_long fmt;
 	int data;
 	int size, nbufs;
+	audio_buf_info info;
 
 	switch (cmd) {
 	case SNDCTL_DSP_RESET:
@@ -5214,6 +5251,14 @@
 		sq_setup(numBufs, size, sound_buffers);
 		sq.max_active = nbufs;
 		return 0;
+	case SNDCTL_DSP_GETOSPACE:
+		info.fragments = sq.max_active - sq.count;
+		info.fragstotal = sq.max_active;
+		info.fragsize = sq.block_size;
+		info.bytes = info.fragments * info.fragsize;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
 
 	default:
 		return mixer_ioctl(inode, file, cmd, arg);
@@ -5308,7 +5353,7 @@
 {
 	char *buffer = state.buf, *mach = "";
 #ifdef CONFIG_PPC
-	char awacs_buf[50];
+	char awacs_buf[64];
 #endif
 	int len = 0;
 
@@ -5576,6 +5621,16 @@
 			printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
 			return;
 		}
+		awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+		if (machine_is_compatible("PowerBook1,1")
+		    || machine_is_compatible("AAPL,PowerBook1998")) {
+			feature_set(np, FEATURE_Sound_CLK_enable);
+			feature_set(np, FEATURE_Sound_power);
+			/* Shorter delay will not work */
+			mdelay(1000);
+		}
+#endif
 		awacs_tx_cmds = (volatile struct dbdma_cmd *)
 			DBDMA_ALIGN(awacs_tx_cmd_space);
 
@@ -5607,7 +5662,10 @@
 			awacs_revision =
 				(in_le32(&awacs->codec_stat) >> 12) & 0xf;
 			if (awacs_revision == 3) {
+				mdelay(100);
 				awacs_write(0x6000);
+				mdelay(2);
+				awacs_write(awacs_reg[1] + MASK_ADDR1);
 				awacs_enable_amp(100 * 0x101);
 			}
 		}
@@ -5629,26 +5687,34 @@
 		/* Powerbooks have odd ways of enabling inputs such as
 		   an expansion-bay CD or sound from an internal modem
 		   or a PC-card modem. */
-		if (machine_is_compatible("AAPL,3400/2400")) {
+		if (machine_is_compatible("AAPL,3400/2400")
+			|| machine_is_compatible("AAPL,3500")) {
 			is_pbook_3400 = 1;
 			/*
 			 * Enable CD and PC-card sound inputs.
 			 * This is done by reading from address
 			 * f301a000, + 0x10 to enable the expansion-bay
 			 * CD sound input, + 0x80 to enable the PC-card
-			 * sound input.  The 0x100 seems to enable the
-			 * MESH and/or its SCSI bus drivers.
+			 * sound input.  The 0x100 enables the SCSI bus
+			 * terminator power.
 			 */
 			in_8((unsigned char *)0xf301a190);
-		} else if (machine_is_compatible("PowerBook1,1")) {
-			np = find_devices("mac-io");
-			if (np && np->n_addrs > 0) {
-				is_pbook_G3 = 1;
-				macio_base = (unsigned char *)
-					ioremap(np->addrs[0].address, 0x40);
-				/* enable CD sound input */
-				out_8(macio_base + 0x37, 3);
+		} else if (machine_is_compatible("PowerBook1,1")
+			   || machine_is_compatible("AAPL,PowerBook1998")) {
+			struct device_node* mio;
+			macio_base = 0;
+			is_pbook_G3 = 1;
+			for (mio = np->parent; mio; mio = mio->parent) {
+				if (strcmp(mio->name, "mac-io") == 0
+				    && mio->n_addrs > 0) {
+					macio_base = (unsigned char *) ioremap
+						(mio->addrs[0].address, 0x40);
+					break;
+				}
 			}
+			/* enable CD sound input */
+			if (macio_base)
+				out_8(macio_base + 0x37, 3);
 		}
 	}
 #endif /* CONFIG_PPC */
diff -u --recursive --new-file v2.3.44/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c
--- v2.3.44/linux/drivers/usb/keybdev.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/usb/keybdev.c	Sun Feb 13 10:30:38 2000
@@ -36,7 +36,7 @@
 #include <linux/module.h>
 #include <linux/kbd_kern.h>
 
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
 
 static unsigned char keybdev_x86_e0s[] = 
 	{ 0x1c, 0x1d, 0x35, 0x2a, 0x38, 0x39, 0x47, 0x48,
@@ -77,7 +77,7 @@
 {
 	if (type != EV_KEY || code > 255) return;
 
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_IA64)
 
 	if (code >= 189) {
   		printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
diff -u --recursive --new-file v2.3.44/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.44/linux/drivers/video/Config.in	Fri Jan 28 15:09:08 2000
+++ linux/drivers/video/Config.in	Sun Feb 13 11:21:42 2000
@@ -73,6 +73,8 @@
    fi
    if [ "$CONFIG_MAC" = "y" ]; then
       define_bool CONFIG_FB_MAC y
+      bool '  Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
+#      bool '  Apple DAFB display support' CONFIG_FB_DAFB
    fi
    if [ "$CONFIG_HP300" = "y" ]; then
       define_bool CONFIG_FB_HP300 y
@@ -88,6 +90,13 @@
    if [ "$CONFIG_VISWS" = "y" ]; then
       tristate '  SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
       define_bool CONFIG_BUS_I2C y
+   fi
+   if [ "$CONFIG_SUN3" = "y" -o "$CONFIG_SUN3X" = "y" ]; then
+      bool 'Sun3 framebuffer support' CONFIG_FB_SUN3
+      if [ "$CONFIG_FB_SUN3" != "n" ]; then
+         bool '  BWtwo support' CONFIG_FB_BWTWO
+         bool '  CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+      fi
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       if [ "$CONFIG_PCI" != "n" ]; then
diff -u --recursive --new-file v2.3.44/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.44/linux/drivers/video/Makefile	Wed Dec 29 13:13:19 1999
+++ linux/drivers/video/Makefile	Sun Feb 13 11:21:43 2000
@@ -60,7 +60,7 @@
 obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
 obj-$(CONFIG_FB_RIVA)             += rivafb.o riva_hw.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
-obj-$(CONFIG_FB_MAC)              += macfb.o
+obj-$(CONFIG_FB_MAC)              += macfb.o macmodes.o
 obj-$(CONFIG_FB_HP300)            += hpfb.o
 obj-$(CONFIG_FB_OF)               += offb.o macmodes.o
 obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
@@ -82,6 +82,8 @@
 obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
 obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
 obj-$(CONFIG_FB_MATROX)           += matroxfb.o
+obj-$(CONFIG_FB_SUN3)             += sun3fb.o
+obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
 
 # Generic Low Level Drivers
diff -u --recursive --new-file v2.3.44/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- v2.3.44/linux/drivers/video/aty128fb.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/video/aty128fb.c	Sun Feb 13 10:47:01 2000
@@ -1675,9 +1675,9 @@
 #endif /* CONFIG_PPC */
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
-    if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
-                      &defaultmode, 8))
-        var = default_var;
+	if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
+			  &defaultmode, 8))
+	    var = default_var;
 #endif
 
 #ifdef CONFIG_PPC
@@ -1685,6 +1685,7 @@
         if (mac_vmode_to_var(default_vmode, default_cmode, &var))
             var = default_var;
 #endif /* CONFIG_PPC */
+    }
 #endif /* MODULE */
 
     if (noaccel)
diff -u --recursive --new-file v2.3.44/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.44/linux/drivers/video/atyfb.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/video/atyfb.c	Sun Feb 13 10:18:03 2000
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.138 2000/02/10 02:52:12 davem Exp $
+/*  $Id: atyfb.c,v 1.139 2000/02/12 22:47:04 davem Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
diff -u --recursive --new-file v2.3.44/linux/drivers/video/bwtwofb.c linux/drivers/video/bwtwofb.c
--- v2.3.44/linux/drivers/video/bwtwofb.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/video/bwtwofb.c	Sun Feb 13 11:21:43 2000
@@ -25,7 +25,7 @@
 
 #include <video/sbusfb.h>
 #include <asm/io.h>
-#ifndef __sparc_v9__
+#if !defined(__sparc_v9__) && !defined(__mc68000__)
 #include <asm/sun4paddr.h>
 #endif
 
@@ -214,9 +214,11 @@
 				case BWTWO_SR_ID_NOCONN:
 					return NULL;
 				default:
+#ifndef CONFIG_FB_SUN3
 					prom_printf("bw2: can't handle SR %02x\n",
 						    status);
 					prom_halt();
+#endif					
 					return NULL; /* fool gcc. */
 			}
 			for ( ; *p; p += 2) {
diff -u --recursive --new-file v2.3.44/linux/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c
--- v2.3.44/linux/drivers/video/fbcon-mac.c	Mon Nov  1 13:56:27 1999
+++ linux/drivers/video/fbcon-mac.c	Sun Feb 13 11:21:43 2000
@@ -331,7 +331,8 @@
   u16 *dest16, pix16;
   u32 *dest32, pix32;
 
-  if (pixel_x < 0 || pixel_y < 0 || pixel_x >= 832 || pixel_y >= 624) {
+  /* There *are* 68k Macs that support more than 832x624, you know :-) */
+  if (pixel_x < 0 || pixel_y < 0 || pixel_x >= p->var.xres || pixel_y >= p->var.yres) {
     int cnt;
     printk ("ERROR: pixel_x == %d, pixel_y == %d", pixel_x, pixel_y);
     for(cnt = 0; cnt < 100000; cnt++)
diff -u --recursive --new-file v2.3.44/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.3.44/linux/drivers/video/fbmem.c	Thu Feb 10 17:11:15 2000
+++ linux/drivers/video/fbmem.c	Sun Feb 13 11:21:43 2000
@@ -98,6 +98,8 @@
 extern int fm2fb_init(void);
 extern int fm2fb_setup(char*);
 extern int q40fb_init(void);
+extern int sun3fb_init(void);
+extern int sun3fb_setup(char *);
 extern int sgivwfb_init(void);
 extern int sgivwfb_setup(char*);
 extern int rivafb_init(void);
@@ -211,6 +213,9 @@
 #ifdef CONFIG_FB_FM2
 	{ "fm2fb", fm2fb_init, fm2fb_setup },
 #endif 
+#ifdef CONFIG_FB_SUN3
+       { "sun3", sun3fb_init, sun3fb_setup },
+#endif
 #ifdef CONFIG_GSP_RESOLVER
 	/* Not a real frame buffer device... */
 	{ "resolver", NULL, resolver_video_setup },
@@ -471,6 +476,9 @@
 	vma->vm_flags |= VM_IO;
 #else
 #if defined(__mc68000__)
+#if defined(CONFIG_SUN3)
+	pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
+#else
 	if (CPU_IS_020_OR_030)
 		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
 	if (CPU_IS_040_OR_060) {
@@ -478,6 +486,7 @@
 		/* Use no-cache mode, serialized */
 		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
 	}
+#endif
 #elif defined(__powerpc__)
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
 #elif defined(__alpha__)
diff -u --recursive --new-file v2.3.44/linux/drivers/video/igafb.c linux/drivers/video/igafb.c
--- v2.3.44/linux/drivers/video/igafb.c	Sat Feb 12 11:22:11 2000
+++ linux/drivers/video/igafb.c	Sun Feb 13 10:18:03 2000
@@ -713,8 +713,8 @@
 	info->mmap_map = kmalloc(4 * sizeof(*info->mmap_map), GFP_ATOMIC);
 	if (!info->mmap_map) {
 		printk("igafb_init: can't alloc mmap_map\n");
-		iounmap(info->io_base);
-		iounmap((void *)info->frame_buffer);
+		iounmap((void *)info->io_base);
+		iounmap(info->frame_buffer);
                 kfree(info);
 		return -ENOMEM;
 	}
@@ -768,8 +768,8 @@
 #endif
 
 	if (!iga_init(info)) {
-		iounmap(info->io_base);
-		iounmap((void *)info->frame_buffer);
+		iounmap((void *)info->io_base);
+		iounmap(info->frame_buffer);
 		if (info->mmap_map)
 			kfree(info->mmap_map);
 		kfree(info);
diff -u --recursive --new-file v2.3.44/linux/drivers/video/macfb.c linux/drivers/video/macfb.c
--- v2.3.44/linux/drivers/video/macfb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/macfb.c	Sun Feb 13 11:21:43 2000
@@ -1,6 +1,22 @@
-/*
- *	We've been given MAC frame buffer info by the booter. Now go set it up
- */
+/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we
+   don't know how to set */
+
+/* (c) 1999 David Huggins-Daines <dhd@debian.org>
+
+   Primarily based on vesafb.c, by Gerd Knorr
+   (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+   Also uses information and code from:
+   
+   The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen
+   Mellinger, Mikael Forselius, Michael Schmitz, and others.
+
+   valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan
+   Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven.
+   
+   This code is free software.  You may copy, modify, and distribute
+   it subject to the terms and conditions of the GNU General Public
+   License, version 2, or any later version, at your convenience. */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -13,6 +29,7 @@
 #include <linux/delay.h>
 #include <linux/nubus.h>
 #include <linux/init.h>
+#include <linux/fb.h>
 
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
@@ -20,16 +37,137 @@
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/macintosh.h>
-#include <linux/fb.h>
+#include <asm/io.h>
+#include <asm/machw.h>
 
 #include <video/fbcon.h>
-/* conditionalize these ?? */
 #include <video/fbcon-mfb.h>
 #include <video/fbcon-cfb2.h>
 #include <video/fbcon-cfb4.h>
 #include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)
+
+/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */
+#define DAC_BASE 0x50f24000
+
+/* Some addresses for the DAFB */
+#define DAFB_BASE 0xf9800200
+
+/* Address for the built-in Civic framebuffer in Quadra AVs */
+#define CIVIC_BASE 0x50f30800	/* Only tested on 660AV! */
+
+/* GSC (Gray Scale Controller) base address */
+#define GSC_BASE 0x50F20000
+
+/* CSC (Color Screen Controller) base address */
+#define CSC_BASE 0x50F20000
+
+static int (*macfb_setpalette) (unsigned int regno, unsigned int red,
+				unsigned int green, unsigned int blue) = NULL;
+static int valkyrie_setpalette (unsigned int regno, unsigned int red,
+				unsigned int green, unsigned int blue);
+static int dafb_setpalette (unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue);
+static int rbv_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue);
+static int mdc_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue);
+static int toby_setpalette (unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue);
+static int civic_setpalette (unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue);
+static int csc_setpalette (unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue);
+
+static volatile struct {
+	unsigned char addr;
+	/* Note: word-aligned */
+	char pad[3];
+	unsigned char lut;
+} *valkyrie_cmap_regs;
+
+static volatile struct {
+	unsigned char addr;
+	unsigned char lut;
+} *v8_brazil_cmap_regs;
+
+static volatile struct {
+	unsigned char addr;
+	char pad1[3]; /* word aligned */
+	unsigned char lut;
+	char pad2[3]; /* word aligned */
+	unsigned char cntl; /* a guess as to purpose */
+} *rbv_cmap_regs;
+
+static volatile struct {
+	unsigned long reset;
+	unsigned long pad1[3];
+	unsigned char pad2[3];
+	unsigned char lut;
+} *dafb_cmap_regs;
+
+static volatile struct {
+	unsigned char addr;	/* OFFSET: 0x00 */
+	unsigned char pad1[15];
+	unsigned char lut;	/* OFFSET: 0x10 */
+	unsigned char pad2[15];
+	unsigned char status;	/* OFFSET: 0x20 */
+	unsigned char pad3[7];
+	unsigned long vbl_addr;	/* OFFSET: 0x28 */
+	unsigned int  status2;	/* OFFSET: 0x2C */
+} *civic_cmap_regs;
+
+static volatile struct {
+	char    pad1[0x40];
+        unsigned char	clut_waddr;	/* 0x40 */
+        char    pad2;
+        unsigned char	clut_data;	/* 0x42 */
+        char	pad3[0x3];
+        unsigned char	clut_raddr;	/* 0x46 */
+} *csc_cmap_regs;
+
+/* We will leave these the way they are for the time being */
+struct mdc_cmap_regs {
+	char pad1[0x200200];
+	unsigned char addr;
+	char pad2[6];
+	unsigned char lut;
+};
 
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
+struct toby_cmap_regs {
+	char pad1[0x90018];
+	unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */
+	char pad2[3];
+	unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */
+};
+
+struct jet_cmap_regs {
+	char pad1[0xe0e000];
+	unsigned char addr;
+	unsigned char lut;
+};
+
+#endif
+
+#define PIXEL_TO_MM(a)	(((a)*10)/28)	/* width in mm at 72 dpi */	
+
+static char* video_base;
+static int   video_size;
+static char* video_vbase;        /* mapped */
+
+/* mode */
+static int  video_bpp;
+static int  video_width;
+static int  video_height;
+static int  video_type = FB_TYPE_PACKED_PIXELS;
+static int  video_visual;
+static int  video_linelength;
+static int  video_cmap_len;
+static int  video_slot = 0;
 
 static struct fb_var_screeninfo macfb_defined={
 	0,0,0,0,	/* W,H, W, H (virtual) load xres,xres_virtual*/
@@ -42,38 +180,36 @@
 	{0,0,0},	/* transparency */
 	0,		/* standard pixel format */
 	FB_ACTIVATE_NOW,
-	274,195,	/* 14" monitor *Mikael Nykvist's anyway* */
-	0,		/* The only way to accelerate a mac is .. */
+	-1, -1,
+	FB_ACCEL_NONE,	/* The only way to accelerate a mac is .. */
 	0L,0L,0L,0L,0L,
 	0L,0L,0,	/* No sync info */
 	FB_VMODE_NONINTERLACED,
 	{0,0,0,0,0,0}
 };
 
-#define NUM_TOTAL_MODES		1
-#define NUM_PREDEF_MODES	1
-
 static struct display disp;
 static struct fb_info fb_info;
+static struct { u_short blue, green, red, pad; } palette[256];
+static union {
+#ifdef FBCON_HAS_CFB16
+    u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+    u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+    u32 cfb32[16];
+#endif
+} fbcon_cmap;
 
-static int inverse = 0;
-
-struct macfb_par
-{
-	void *unused;
-};
-
-static int currcon = 0;
-static int current_par_valid = 0;
-struct macfb_par current_par;
-
-static int mac_xres,mac_yres,mac_depth, mac_xbytes, mac_vxres;
-static unsigned long mac_videobase;
-static unsigned long mac_videosize;
+static int             inverse   = 0;
+static int             vidtest   = 0;
+static int             currcon   = 0;
 
-	/*
-	 * Open/Release the frame buffer device
-	 */
+/*
+ * Open/Release the frame buffer device
+ */
 
 static int macfb_open(struct fb_info *info, int user)
 {
@@ -90,105 +226,32 @@
 	return(0);
 }
 
-static void macfb_encode_var(struct fb_var_screeninfo *var, 
-				struct macfb_par *par)
-{
-	memset(var, 0, sizeof(struct fb_var_screeninfo));
-	var->xres=mac_xres;
-	var->yres=mac_yres;
-	var->xres_virtual=mac_vxres;
-	var->yres_virtual=var->yres;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->bits_per_pixel = mac_depth;
-	var->grayscale=0;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->height= -1;
-	var->width= -1;
-	var->vmode=FB_VMODE_NONINTERLACED;
-	var->pixclock=0;
-	var->sync=0;
-	var->left_margin=0;
-	var->right_margin=0;
-	var->upper_margin=0;
-	var->lower_margin=0;
-	var->hsync_len=0;
-	var->vsync_len=0;
-	return;
-}
-
-
-static void macfb_get_par(struct macfb_par *par)
-{
-	*par=current_par;
-}
-
-static void macfb_set_par(struct macfb_par *par)
-{
-	current_par_valid=1;
-}
-
-static int fb_update_var(int con, struct fb_info *info)
+static int macfb_update_var(int con, struct fb_info *info)
 {
 	return 0;
 }
 
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
-	struct macfb_par par;
-	
-	macfb_get_par(&par);
-	macfb_encode_var(var, &par);
-	return 0;
-}
-
-extern int console_loglevel;
-
-static void macfb_encode_fix(struct fb_fix_screeninfo *fix, 
-				struct macfb_par *par)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id,"Macintosh");
-
-	/*
-	 * fbmem.c accepts non page aligned mappings now!
-	 */
-	fix->smem_start=mac_videobase;
-	fix->smem_len=mac_videosize;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	if (mac_depth == 1)
-		fix->visual = FB_VISUAL_MONO01;
-	else
-		fix->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
-	fix->xpanstep=0;
-	fix->ypanstep=0;
-	fix->ywrapstep=0;
-	fix->line_length=mac_xbytes;
-	return;
-}
-
 static int macfb_get_fix(struct fb_fix_screeninfo *fix, int con,
 			 struct fb_info *info)
 {
-	struct macfb_par par;
-	macfb_get_par(&par);
-	macfb_encode_fix(fix, &par);
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "Mac Generic");
+
+	fix->smem_start = video_base;
+	fix->smem_len = video_size;
+	fix->type = video_type;
+	fix->visual = video_visual;
+	fix->xpanstep = 0;
+	fix->ypanstep = 0;
+	fix->line_length=video_linelength;
 	return 0;
 }
 
 static int macfb_get_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-	struct macfb_par par;
 	if(con==-1)
-	{
-		macfb_get_par(&par);
-		macfb_encode_var(var, &par);
-	}
+		memcpy(var, &macfb_defined, sizeof(struct fb_var_screeninfo));
 	else
 		*var=fb_display[con].var;
 	return 0;
@@ -204,9 +267,10 @@
 	else
 		display = &disp;	/* used during initialization */
 
-	macfb_get_fix(&fix, con, 0);
+	macfb_get_fix(&fix, con, &fb_info);
 
-	display->screen_base = fix.smem_start;
+	memset(display, 0, sizeof(struct display));
+	display->screen_base = video_vbase;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -215,235 +279,586 @@
 	display->line_length = fix.line_length;
 	display->next_line = fix.line_length;
 	display->can_soft_blank = 0;
-	display->inverse =
-	    (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+	display->inverse = inverse;
+	display->scrollmode = SCROLL_YREDRAW;
+	macfb_get_var(&display->var, -1, &fb_info);
 
-	switch (mac_depth) {
+	switch (video_bpp) {
 #ifdef FBCON_HAS_MFB
-	    case 1:
+	case 1:
 		display->dispsw = &fbcon_mfb;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB2
-	    case 2:
+	case 2:
 		display->dispsw = &fbcon_cfb2;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB4
-	    case 4:
+	case 4:
 		display->dispsw = &fbcon_cfb4;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB8
-	    case 8:
+	case 8:
 		display->dispsw = &fbcon_cfb8;
 		break;
 #endif
-	    default:
-		display->dispsw = &fbcon_dummy;
+#ifdef FBCON_HAS_CFB16
+	case 15:
+	case 16:
+		display->dispsw = &fbcon_cfb16;
+		display->dispsw_data = fbcon_cmap.cfb16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		display->dispsw = &fbcon_cfb24;
+		display->dispsw_data = fbcon_cmap.cfb24;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		display->dispsw = &fbcon_cfb32;
+		display->dispsw_data = fbcon_cmap.cfb32;
 		break;
+#endif
+	default:
+		display->dispsw = &fbcon_dummy;
+		return;
 	}
 }
 
 static int macfb_set_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-	int err;
+	static int first = 1;
+
+	if (var->xres           != macfb_defined.xres           ||
+	    var->yres           != macfb_defined.yres           ||
+	    var->xres_virtual   != macfb_defined.xres_virtual   ||
+	    var->yres_virtual   != macfb_defined.yres           ||
+	    var->xoffset                                        ||
+	    var->bits_per_pixel != macfb_defined.bits_per_pixel ||
+	    var->nonstd) {
+		if (first) {
+			printk("macfb does not support changing the video mode\n");
+			first = 0;
+		}
+		return -EINVAL;
+	}
+
+	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
+		return 0;
+
+	if (var->yoffset)
+		return -EINVAL;
+	return 0;
+}
+
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2)
+static int valkyrie_setpalette (unsigned int regno, unsigned int red,
+				unsigned int green, unsigned int blue)
+{
+	unsigned long flags;
+	
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	save_flags(flags);
+	cli();
+	
+	/* tell clut which address to fill */
+	writeb(regno, &valkyrie_cmap_regs->addr);
+	nop();
+
+	/* send one color channel at a time */
+	writeb(red, &valkyrie_cmap_regs->lut);
+	nop();
+	writeb(green, &valkyrie_cmap_regs->lut);
+	nop();
+	writeb(blue, &valkyrie_cmap_regs->lut);
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* Unlike the Valkyrie, the DAFB cannot set individual colormap
+   registers.  Therefore, we do what the MacOS driver does (no
+   kidding!) and simply set them one by one until we hit the one we
+   want. */
+static int dafb_setpalette (unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue)
+{
+	/* FIXME: really, really need to use ioremap() here,
+           phys_to_virt() doesn't work anymore */
+	static int lastreg = -1;
+	unsigned long flags;
+	
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	save_flags(flags);
+	cli();
+	
+	/* fbcon will set an entire colourmap, but X won't.  Hopefully
+	   this should accomodate both of them */
+	if (regno != lastreg+1) {
+		int i;
+		
+		/* Stab in the dark trying to reset the CLUT pointer */
+		writel(0, &dafb_cmap_regs->reset);
+		nop();
+		
+		/* Loop until we get to the register we want */
+		for (i = 0; i < regno; i++) {
+			writeb(palette[i].red >> 8, &dafb_cmap_regs->lut);
+			nop();
+			writeb(palette[i].green >> 8, &dafb_cmap_regs->lut);
+			nop();
+			writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut);
+			nop();
+		}
+	}
+		
+	writeb(red, &dafb_cmap_regs->lut);
+	nop();
+	writeb(green, &dafb_cmap_regs->lut);
+	nop();
+	writeb(blue, &dafb_cmap_regs->lut);
+	
+	restore_flags(flags);
+	
+	lastreg = regno;
+	return 0;
+}
+
+/* V8 and Brazil seem to use the same DAC.  Sonora does as well. */
+static int v8_brazil_setpalette (unsigned int regno, unsigned int red,
+				 unsigned int green, unsigned int blue)
+{
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno;
+	unsigned long flags;
+
+	if (video_bpp>8) return 1; /* failsafe */
+
+	save_flags(flags);
+	cli();
+
+	/* On these chips, the CLUT register numbers are spread out
+	   across the register space.  Thus:
+
+	   In 8bpp, all regnos are valid.
+	   
+	   In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
+	   
+	   In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */
+  	_regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
+	writeb(_regno, &v8_brazil_cmap_regs->addr); nop();
+
+	/* send one color channel at a time */
+	writeb(_red, &v8_brazil_cmap_regs->lut); nop();
+	writeb(_green, &v8_brazil_cmap_regs->lut); nop();
+	writeb(_blue, &v8_brazil_cmap_regs->lut);
+
+	restore_flags(flags);
+	
+	return 0;
+}
+
+static int rbv_setpalette (unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue)
+{
+	/* use MSBs */
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno;
+	unsigned long flags;
+
+	if (video_bpp>8) return 1; /* failsafe */
+
+	save_flags(flags);
+	cli();
+	
+	/* From the VideoToolbox driver.  Seems to be saying that
+	 * regno #254 and #255 are the important ones for 1-bit color,
+	 * regno #252-255 are the important ones for 2-bit color, etc.
+	 */
+	_regno = regno + (256-(1<<video_bpp));
+
+	/* reset clut? (VideoToolbox sez "not necessary") */
+	writeb(0xFF, &rbv_cmap_regs->cntl); nop();
+	
+	/* tell clut which address to use. */
+	writeb(_regno, &rbv_cmap_regs->addr); nop();
+	
+	/* send one color channel at a time. */
+	writeb(_red,   &rbv_cmap_regs->lut); nop();
+	writeb(_green, &rbv_cmap_regs->lut); nop();
+	writeb(_blue,  &rbv_cmap_regs->lut);
+	
+	restore_flags(flags);
+	/* done. */
+	return 0;
+}
+
+/* Macintosh Display Card (8x24) */
+static int mdc_setpalette(unsigned int regno, unsigned int red,
+			  unsigned int green, unsigned int blue)
+{
+	volatile struct mdc_cmap_regs *cmap_regs =
+		nubus_slot_addr(video_slot);
+	/* use MSBs */
+	unsigned char _red  =red>>8;
+	unsigned char _green=green>>8;
+	unsigned char _blue =blue>>8;
+	unsigned char _regno=regno;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	
+	/* the nop's are there to order writes. */
+	writeb(_regno, &cmap_regs->addr); nop();
+	writeb(_red, &cmap_regs->lut);    nop();
+	writeb(_green, &cmap_regs->lut);  nop();
+	writeb(_blue, &cmap_regs->lut);
+
+	restore_flags(flags);
+	return 0;
+}
+
+/* Toby frame buffer */
+static int toby_setpalette(unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue)
+{
+	volatile struct toby_cmap_regs *cmap_regs =
+		nubus_slot_addr(video_slot);
+	/* use MSBs */
+	unsigned char _red  =~(red>>8);
+	unsigned char _green=~(green>>8);
+	unsigned char _blue =~(blue>>8);
+	unsigned char _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp);
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	
+	writeb(_regno, &cmap_regs->addr); nop();
+	writeb(_red, &cmap_regs->lut);    nop();
+	writeb(_green, &cmap_regs->lut);  nop();
+	writeb(_blue, &cmap_regs->lut);
+
+	restore_flags(flags);
+	return 0;
+}
+
+/* Jet frame buffer */
+static int jet_setpalette(unsigned int regno, unsigned int red,
+			  unsigned int green, unsigned int blue)
+{
+	volatile struct jet_cmap_regs *cmap_regs =
+		nubus_slot_addr(video_slot);
+	/* use MSBs */
+	unsigned char _red   = (red>>8);
+	unsigned char _green = (green>>8);
+	unsigned char _blue  = (blue>>8);
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
 	
-	if ((err=do_fb_set_var(var, 1)))
-		return err;
+	writeb(regno, &cmap_regs->addr); nop();
+	writeb(_red, &cmap_regs->lut); nop();
+	writeb(_green, &cmap_regs->lut); nop();
+	writeb(_blue, &cmap_regs->lut);
+
+	restore_flags(flags);
 	return 0;
 }
 
 /*
- * Color map handling - hardcoded maps!! 
+ * Civic framebuffer -- Quadra AV built-in video.  A chip
+ * called Sebastian holds the actual color palettes, and
+ * apparently, there are two different banks of 512K RAM 
+ * which can act as separate framebuffers for doing video
+ * input and viewing the screen at the same time!  The 840AV
+ * Can add another 1MB RAM to give the two framebuffers 
+ * 1MB RAM apiece.
  *
- * 2.0 color map primitives, copied from atafb.c
+ * FIXME: this doesn't seem to work anymore.
  */
- 
-/*
- * should be kmalloc'ed on request
- */
-static short red256[256], green256[256], blue256[256];
+static int civic_setpalette (unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue)
+{
+	static int lastreg = -1;
+	unsigned long flags;
+	int clut_status;
+	
+	if (video_bpp > 8) return 1; /* failsafe */
 
-static short red16[]=
-	{ 0x0000,0x0000,0x0000,0x0000,0x8080,0x8080,0x8080,0xc0c0,
-	  0x8080,0x0000,0x0000,0x0000,0xffff,0xffff,0xffff,0xffff};
-static short green16[]=
-	{ 0x0000,0x0000,0x8080,0x8080,0x0000,0x0000,0x8080,0xc0c0,
-	  0x8080,0x0000,0xffff,0xffff,0x0000,0x0000,0xffff,0xffff};
-static short blue16[]=
-	{ 0x0000,0x8080,0x0000,0x8080,0x0000,0x8080,0x0000,0xc0c0,
-	  0x8080,0xffff,0x0000,0xffff,0x0000,0xffff,0x0000,0xffff};
-
-static short red4[]=
-	{ 0x0000,0x8080,0xffff,0xffff};
-static short green4[]=
-	{ 0x0000,0x8080,0x0000,0xffff};
-static short blue4[]=
-	{ 0x0000,0x8080,0x0000,0xffff};
-
-static short red2[]=
-	{ 0x0000,0xffff};
-static short green2[]=
-	{ 0x0000,0xffff};
-static short blue2[]=
-	{ 0x0000,0xffff};
-
-struct fb_cmap default_256_colors = { 0, 256, red256, green256, blue256, NULL };
-struct fb_cmap default_16_colors  = { 0, 16, red16, green16, blue16, NULL };
-struct fb_cmap default_4_colors   = { 0, 4, red4, green4, blue4, NULL };
-struct fb_cmap default_2_colors   = { 0, 2, red2, green2, blue2, NULL };
-
-static int mac_set_cmap256(struct fb_cmap* cmap)
-{
-	int i,start;
-	unsigned short *red,*green,*blue;
-	unsigned short cval[] = {0xffff, 0xcccc, 0x9999, 
-				 0x6666, 0x3333, 0x0000 };
-	unsigned short gval[] = {0x0a0a, 0x1414, 0x1e1e,
-				 0x2828, 0x3232, 0x3c3c,
-				 0x4646, 0x5050, 0x5a5a,
-				 0x6464, 0x6e6e, 0x7878,
-				 0x8282, 0x8c8c, 0x9696,
-				 0xa0a0, 0xaaaa, 0xb4b4,
-				 0xbebe, 0xc8c8, 0xd2d2,
-				 0xdcdc, 0xe6e6, 0xf0f0};
-
-	red=cmap->red;
-	green=cmap->green;
-	blue=cmap->blue;
-	start=cmap->start;
+	red   >>= 8;
+	green >>= 8;
+	blue  >>= 8;
 
-	if (start < 0)
-		return -EINVAL;
-	if (cmap->len < 255)
-		return -EINVAL;
-	/* 16 ANSI colors */
-	for (i=0 ; i < 16 ; i++) {
-		*red++   = red16[i];
-		*green++ = green16[i];
-		*blue++  = blue16[i];
+	save_flags(flags);
+	cli();
+	
+	/*
+	 * Set the register address
+	 */
+	writeb(regno, &civic_cmap_regs->addr); nop();
+
+	/*
+	 * Wait for VBL interrupt here;
+	 * They're usually not enabled from Penguin, so we won't check
+	 */
+#if 0
+	{
+#define CIVIC_VBL_OFFSET	0x120
+		volatile unsigned long *vbl = readl(civic_cmap_regs->vbl_addr + CIVIC_VBL_OFFSET);
+		/* do interrupt setup stuff here? */
+		*vbl = 0L; nop();	/* clear */
+		*vbl = 1L; nop();	/* set */
+		while (*vbl != 0L)	/* wait for next vbl */
+		{
+			usleep(10);	/* needed? */
+		}
+		/* do interrupt shutdown stuff here? */
 	}
-	/* 216 colors (6x6x6) map) */
-	for (i=16 ; i < 232 ; i++) {
-		*red++   = cval[(i-16)/36];
-		*green++ = cval[((i-16)/6)%6];
-		*blue++  = cval[(i-16)%6];
+#endif
+
+	/*
+	 * Grab a status word and do some checking;
+	 * Then finally write the clut!
+	 */
+	clut_status =  readb(&civic_cmap_regs->status2);
+
+	if ((clut_status & 0x0008) == 0)
+	{
+#if 0
+		if ((clut_status & 0x000D) != 0)
+		{
+			writeb(0x00, &civic_cmap_regs->lut); nop();
+			writeb(0x00, &civic_cmap_regs->lut); nop();
+		}
+#endif
+
+		writeb(  red, &civic_cmap_regs->lut); nop();
+		writeb(green, &civic_cmap_regs->lut); nop();
+		writeb( blue, &civic_cmap_regs->lut); nop();
+		writeb( 0x00, &civic_cmap_regs->lut); nop();
 	}
-	/* 24 grays */
-	for (i=232 ; i < 256 ; i++) {
-		*red = *green = *blue = gval[i-232];
-		red++;
-		green++;
-		blue++;
+	else
+	{
+		unsigned char junk;
+
+		junk = readb(&civic_cmap_regs->lut); nop();
+		junk = readb(&civic_cmap_regs->lut); nop();
+		junk = readb(&civic_cmap_regs->lut); nop();
+		junk = readb(&civic_cmap_regs->lut); nop();
+
+		if ((clut_status & 0x000D) != 0)
+		{
+			writeb(0x00, &civic_cmap_regs->lut); nop();
+			writeb(0x00, &civic_cmap_regs->lut); nop();
+		}
+
+		writeb(  red, &civic_cmap_regs->lut); nop();
+		writeb(green, &civic_cmap_regs->lut); nop();
+		writeb( blue, &civic_cmap_regs->lut); nop();
+		writeb( junk, &civic_cmap_regs->lut); nop();
 	}
+
+	restore_flags(flags);
+
+	lastreg = regno;
+	return 0;
+}
+
+/*
+ * The CSC is the framebuffer on the PowerBook 190 series
+ * (and the 5300 too, but that's a PowerMac). This function
+ * brought to you in part by the ECSC driver for MkLinux.
+ */
+
+static int csc_setpalette (unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue)
+{
+	mdelay(1);
+	csc_cmap_regs->clut_waddr = regno;
+	csc_cmap_regs->clut_data = red;
+	csc_cmap_regs->clut_data = green;
+	csc_cmap_regs->clut_data = blue;
 	return 0;
 }
 
-static struct fb_cmap * mac_get_default_cmap(int bpp)
+#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB4 || FBCON_HAS_CFB2 */
+
+static int macfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			   unsigned *blue, unsigned *transp,
+			   struct fb_info *fb_info)
 {
-	if (bpp == 1)
-		return &default_2_colors;
-	if (bpp == 2)
-		return &default_4_colors;
-	if (bpp == 4)
-		return &default_16_colors;
-	return &default_256_colors;
-}
-
-static void memcpy_fs(int fsfromto, void *to, void *from, int len)
-{
-    switch (fsfromto) {
-    	case 0:
-    	    memcpy(to, from, len);
-    	    return;
-    	case 1:
-    	    copy_from_user(to, from, len);
-    	    return;
-    	case 2:
-    	    copy_to_user(to, from, len);
-    	    return;
-    }
+	/*
+	 *  Read a single color register and split it into colors/transparent.
+	 *  Return != 0 for invalid regno.
+	 */
+
+	if (regno >= video_cmap_len)
+		return 1;
+
+	*red   = palette[regno].red;
+	*green = palette[regno].green;
+	*blue  = palette[regno].blue;
+	*transp = 0;
+	return 0;
 }
 
-static void copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
+static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *fb_info)
 {
-	int size;
-	int tooff=0, fromoff=0;
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+	
+	if (regno >= video_cmap_len)
+		return 1;
 
-	if (to->start > from->start)
-		fromoff=to->start-from->start;
-	else
-		tooff=from->start-to->start;			
-	size=to->len-tooff;
-	if (size > from->len-fromoff)
-		size=from->len-fromoff;
-	if (size < 0)
+	palette[regno].red   = red;
+	palette[regno].green = green;
+	palette[regno].blue  = blue;
+
+	switch (video_bpp) {
+#ifdef FBCON_HAS_MFB
+	case 1:
+		/* We shouldn't get here */
+		break;
+#endif
+#ifdef FBCON_HAS_CFB2
+	case 2:
+		if (macfb_setpalette)
+			macfb_setpalette(regno, red, green, blue);
+		else
+			return 1;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB4
+	case 4:
+		if (macfb_setpalette)
+			macfb_setpalette(regno, red, green, blue);
+		else
+			return 1;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		if (macfb_setpalette)
+			macfb_setpalette(regno, red, green, blue);
+		else
+			return 1;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 15:
+	case 16:
+		/* 1:5:5:5 */
+		fbcon_cmap.cfb16[regno] =
+			((red   & 0xf800) >>  1) |
+			((green & 0xf800) >>  6) |
+			((blue  & 0xf800) >> 11) |
+			((transp != 0) << 15);
+		break;
+#endif
+		/* I'm pretty sure that one or the other of these
+		   doesn't exist on 68k Macs */
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		fbcon_cmap.cfb24[regno] =
+			(red   << macfb_defined.red.offset)   |
+			(green << macfb_defined.green.offset) |
+			(blue  << macfb_defined.blue.offset);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		fbcon_cmap.cfb32[regno] =
+			(red   << macfb_defined.red.offset)   |
+			(green << macfb_defined.green.offset) |
+			(blue  << macfb_defined.blue.offset);
+		break;
+#endif
+    }
+    return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+	if (con != currcon)
 		return;
-	size*=sizeof(unsigned short);
-	memcpy_fs(fsfromto, to->red+tooff, from->red+fromoff, size);
-	memcpy_fs(fsfromto, to->green+tooff, from->green+fromoff, size);
-	memcpy_fs(fsfromto, to->blue+tooff, from->blue+fromoff, size);
-	if (from->transp && to->transp)
-		memcpy_fs(fsfromto, to->transp+tooff, from->transp+fromoff, size);
+	if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, 1, macfb_setcolreg, info);
+	else
+		fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
+			    macfb_setcolreg, info);
 }
- 
+
 static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			  struct fb_info *info)
 {
-#if 0
-	printk("macfb_get_cmap: not supported!\n");
-	/* interferes with X11 */
-	if (console_loglevel < 7)
-		return -EINVAL;
 	if (con == currcon) /* current console? */
-		return fb_get_cmap(cmap, kspc, 0 /*offb_getcolreg*/, info);
+		return fb_get_cmap(cmap, kspc, macfb_getcolreg, info);
 	else if (fb_display[con].cmap.len) /* non default colormap? */
 		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
 	else
-		fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel),
+		fb_copy_cmap(fb_default_cmap(video_cmap_len),
 		     cmap, kspc ? 0 : 2);
-#endif
-	copy_cmap(mac_get_default_cmap(fb_display[con].var.bits_per_pixel),
-	     cmap, kspc ? 0 : 2);
 	return 0;
-
 }
 
 static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 			  struct fb_info *info)
 {
-#if 0
-	printk("macfb_set_cmap: not supported!\n");
-	if (console_loglevel < 7)
-		return -EINVAL;
+	int err;
+
 	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
-		if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-				 1<<fb_display[con].var.bits_per_pixel, 0)))
-		return err;
+		err = fb_alloc_cmap(&fb_display[con].cmap,video_cmap_len,0);
+		if (err)
+			return err;
 	}
 	if (con == currcon)			/* current console? */
-		return fb_set_cmap(cmap, kspc, 1 /*offb_setcolreg*/, info);
+		return fb_set_cmap(cmap, kspc, macfb_setcolreg, info);
 	else
 		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
-#endif
 	return 0;
 }
 
-static int macfb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *info)
+static int macfb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg, int con,
+		       struct fb_info *info)
 {
-	/* no panning */
-	printk("macfb_pan: not supported!\n");
 	return -EINVAL;
 }
 
-static int macfb_ioctl(struct inode *inode, struct file *file, 
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info)
+static int macfb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info)
 {
-	printk("macfb_ioctl: not supported!\n");
 	return -EINVAL;
 }
 
@@ -456,137 +871,405 @@
 	macfb_get_cmap,
 	macfb_set_cmap,
 	macfb_pan_display,
-	macfb_ioctl
+	macfb_ioctl,
+	NULL
 };
 
-int __init macfb_setup(char *options)
+void macfb_setup(char *options, int *ints)
 {
-    char *this_opt;
-
-    fb_info.fontname[0] = '\0';
-
-    if (!options || !*options)
-		return 0;
-     
-    for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
-	if (!*this_opt) continue;
-
-	if (! strcmp(this_opt, "inverse"))
-		inverse=1;
-	else if (!strncmp(this_opt, "font:", 5)) {
-	   strcpy(fb_info.fontname, this_opt+5);
-	   printk("macfb_setup: option %s\n", this_opt);
+	char *this_opt;
+	
+	fb_info.fontname[0] = '\0';
+	
+	if (!options || !*options)
+		return;
+	
+	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+		if (!*this_opt) continue;
+		
+		if (! strcmp(this_opt, "inverse"))
+			inverse=1;
+		else if (!strncmp(this_opt, "font:", 5))
+			strcpy(fb_info.fontname, this_opt+5);
+		/* This means "turn on experimental CLUT code" */
+		else if (!strcmp(this_opt, "vidtest"))
+			vidtest=1;
 	}
-    }
-    return 0;
 }
 
 static int macfb_switch(int con, struct fb_info *info)
 {
-	do_fb_set_var(&fb_display[con].var,1);
-	currcon=con;
-	return 0;
+	/* Do we have to save the colormap? */
+	if (fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap, 1, macfb_getcolreg,
+			    info);
+	
+	currcon = con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	macfb_update_var(con, info);
+	return 1;
 }
 
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
 static void macfb_blank(int blank, struct fb_info *info)
 {
 	/* Not supported */
 }
 
-/*
- *	Nubus call back. This will give us our board identity and also
- *	other useful info we need later
- */
- 
-static int nubus_video_card(struct nubus_device_specifier *ns, int slot, struct nubus_type *nt)
+void __init macfb_init(void)
 {
-	if(nt->category==NUBUS_CAT_DISPLAY)
-		return 0;
-	/* Claim all video cards. We don't yet do driver specifics though. */
-	return -ENODEV;
-}
-
-static struct nubus_device_specifier nb_video={
-	nubus_video_card,
-	NULL
-};
-
-int __init macfb_init(void)
-{
-	/* nubus_remap the video .. */
+	struct nubus_dev* ndev = NULL;
+	int video_is_nubus = 0;
 
 	if (!MACH_IS_MAC) 
-		return -ENXIO;
-
-	mac_xres=mac_bi_data.dimensions&0xFFFF;
-	mac_yres=(mac_bi_data.dimensions&0xFFFF0000)>>16;
-	mac_depth=mac_bi_data.videodepth;
-	mac_xbytes=mac_bi_data.videorow;
-	mac_vxres = (mac_xbytes/mac_depth)*8;
-	mac_videosize=mac_xbytes*mac_yres;
-	mac_videobase=mac_bi_data.videoaddr;
-
-	printk("macfb_init: xres %d yres %d bpp %d addr %lx size %ld \n",
-		mac_xres, mac_yres, mac_depth, mac_videobase, mac_videosize);
+		return;
 
+	/* There can only be one internal video controller anyway so
+	   we're not too worried about this */
+	video_width      = mac_bi_data.dimensions & 0xFFFF;
+	video_height     = mac_bi_data.dimensions >> 16;
+	video_bpp        = mac_bi_data.videodepth;
+	video_linelength = mac_bi_data.videorow;
+	video_size       = video_linelength * video_height;
+	/* Note: physical address (since 2.1.127) */
+	video_base       = (void*) mac_bi_data.videoaddr;
+	/* This is actually redundant with the initial mappings.
+	   However, there are some non-obvious aspects to the way
+	   those mappings are set up, so this is in fact the safest
+	   way to ensure that this driver will work on every possible
+	   Mac */
+	video_vbase	 = ioremap(mac_bi_data.videoaddr, video_size);
+	
+	printk("macfb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n",
+	       video_base, video_vbase, video_size/1024);
+	printk("macfb: mode is %dx%dx%d, linelength=%d\n",
+	       video_width, video_height, video_bpp, video_linelength);
+	
 	/*
 	 *	Fill in the available video resolution
 	 */
 	 
-	 macfb_defined.xres=mac_xres;
-	 macfb_defined.yres=mac_yres;
-	 macfb_defined.xres_virtual=mac_vxres;
-	 macfb_defined.yres_virtual=mac_yres;
-	 macfb_defined.bits_per_pixel=mac_depth;
-	 
-	 
-	/*
-	 *	Let there be consoles..
-	 */
-	strcpy(fb_info.modename, "Macintosh Builtin ");
-	fb_info.changevar = NULL;
-	fb_info.node = -1;
-	fb_info.fbops = &macfb_ops;
-	fb_info.disp=&disp;
-	fb_info.switch_con=&macfb_switch;
-	fb_info.updatevar=&fb_update_var;
-	fb_info.blank=&macfb_blank;
-	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	do_fb_set_var(&macfb_defined,1);
-
-	macfb_get_var(&disp.var, -1, &fb_info);
-	macfb_set_disp(-1);
-
-	/*
-	 *	Fill in the 8 bit color table if required
-	 */
-	if (mac_depth == 8)
-		mac_set_cmap256(&default_256_colors);
-	 	
-	/*
-	 *	Register the nubus hook
+	macfb_defined.xres           = video_width;
+	macfb_defined.yres           = video_height;
+	macfb_defined.xres_virtual   = video_width;
+	macfb_defined.yres_virtual   = video_height;
+	macfb_defined.bits_per_pixel = video_bpp;
+	macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres);
+	macfb_defined.width  = PIXEL_TO_MM(macfb_defined.xres);	 
+
+	printk("macfb: scrolling: redraw\n");
+	macfb_defined.yres_virtual = video_height;
+
+	/* some dummy values for timing to make fbset happy */
+	macfb_defined.pixclock     = 10000000 / video_width * 1000 / video_height;
+	macfb_defined.left_margin  = (video_width / 8) & 0xf8;
+	macfb_defined.right_margin = 32;
+	macfb_defined.upper_margin = 16;
+	macfb_defined.lower_margin = 4;
+	macfb_defined.hsync_len    = (video_width / 8) & 0xf8;
+	macfb_defined.vsync_len    = 4;
+
+	switch (video_bpp) {
+	case 1:
+		/* XXX: I think this will catch any program that tries
+		   to do FBIO_PUTCMAP when the visual is monochrome */
+		video_cmap_len = 0;
+		video_visual = FB_VISUAL_MONO01;
+		break;
+	case 2:
+	case 4:
+	case 8:
+		macfb_defined.red.length = video_bpp;
+		macfb_defined.green.length = video_bpp;
+		macfb_defined.blue.length = video_bpp;
+		video_cmap_len = 1 << video_bpp;
+		video_visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 16:
+		macfb_defined.transp.offset = 15;
+		macfb_defined.transp.length = 1;
+		macfb_defined.red.offset = 10;
+		macfb_defined.red.length = 5;
+		macfb_defined.green.offset = 5;
+		macfb_defined.green.length = 5;
+		macfb_defined.blue.offset = 0;
+		macfb_defined.blue.length = 5;
+		printk("macfb: directcolor: "
+		       "size=1:5:5:5, shift=15:10:5:0\n");
+		video_cmap_len = 16;
+		/* Should actually be FB_VISUAL_DIRECTCOLOR, but this
+		   works too */
+		video_visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 24:
+	case 32:
+		/* XXX: have to test these... can any 68k Macs
+		   actually do this on internal video? */
+		macfb_defined.red.offset = 16;
+		macfb_defined.red.length = 8;
+		macfb_defined.green.offset = 8;
+		macfb_defined.green.length = 8;
+		macfb_defined.blue.offset = 0;
+		macfb_defined.blue.length = 8;
+		printk("macfb: truecolor: "
+		       "size=0:8:8:8, shift=0:16:8:0\n");
+		video_cmap_len = 16;
+		video_visual = FB_VISUAL_TRUECOLOR;
+	default:
+		video_cmap_len = 0;
+		video_visual = FB_VISUAL_MONO01;
+		printk("macfb: unknown or unsupported bit depth: %d\n", video_bpp);
+		break;
+	}
+	
+	/* Hardware dependent stuff */
+	/*  We take a wild guess that if the video physical address is
+	 *  in nubus slot space, that the nubus card is driving video.
+	 *  Penguin really ought to tell us whether we are using internal
+	 *  video or not.
 	 */
-	 
-	register_nubus_device(&nb_video);
+	/* Hopefully we only find one of them.  Otherwise our NuBus
+           code is really broken :-) */
 
-	if (register_framebuffer(&fb_info) < 0)
+	while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
+		!= NULL)
 	{
-		return -EINVAL;
+		if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
+		      && (mac_bi_data.videoaddr <
+			  (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
+			continue;
+		video_is_nubus = 1;
+		/* We should probably just use the slot address... */
+		video_slot = ndev->board->slot;
+
+		switch(ndev->dr_hw) {
+		case NUBUS_DRHW_APPLE_MDC:
+			strcpy( fb_info.modename, "Macintosh Display Card" );
+			macfb_setpalette = mdc_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			break;
+		case NUBUS_DRHW_APPLE_TFB:
+			strcpy( fb_info.modename, "Toby" );
+			macfb_setpalette = toby_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			break;
+		case NUBUS_DRHW_APPLE_JET:
+			strcpy(fb_info.modename, "Jet");
+			macfb_setpalette = jet_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			break;			
+		default:
+			strcpy( fb_info.modename, "Generic NuBus" );
+			break;
+		}
 	}
 
-	printk("fb%d: %s frame buffer device using %ldK of video memory\n",
-	       GET_FB_IDX(fb_info.node), fb_info.modename, mac_videosize>>10);
-	return 0;
-}
+	/* If it's not a NuBus card, it must be internal video */
+	/* FIXME: this function is getting way too big.  (this driver
+           is too...) */
+	if (!video_is_nubus)
+		switch( mac_bi_data.id )
+		{
+			/* These don't have onboard video.  Eventually, we may
+			   be able to write separate framebuffer drivers for
+			   them (tobyfb.c, hiresfb.c, etc, etc) */
+		case MAC_MODEL_II:
+		case MAC_MODEL_IIX:
+		case MAC_MODEL_IICX:
+		case MAC_MODEL_IIFX:
+			strcpy( fb_info.modename, "Generic NuBus" );
+			break;
+
+			/* Valkyrie Quadras */
+		case MAC_MODEL_Q630:
+			/* I'm not sure about this one */
+		case MAC_MODEL_P588:
+			strcpy( fb_info.modename, "Valkyrie built-in" );
+			macfb_setpalette = valkyrie_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+
+			/* DAFB Quadras */
+			/* Note: these first four have the v7 DAFB, which is
+			   known to be rather unlike the ones used in the
+			   other models */
+		case MAC_MODEL_P475:
+		case MAC_MODEL_P475F:
+		case MAC_MODEL_P575:
+		case MAC_MODEL_Q605:
+	
+		case MAC_MODEL_Q800:
+		case MAC_MODEL_Q650:
+		case MAC_MODEL_Q610:
+		case MAC_MODEL_C650:
+		case MAC_MODEL_C610:
+		case MAC_MODEL_Q700:
+		case MAC_MODEL_Q900:
+		case MAC_MODEL_Q950:
+			strcpy( fb_info.modename, "DAFB built-in" );
+			macfb_setpalette = dafb_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
+			break;
+
+			/* LC II uses the V8 framebuffer */
+		case MAC_MODEL_LCII:
+			strcpy( fb_info.modename, "V8 built-in" );
+			macfb_setpalette = v8_brazil_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+		
+			/* IIvi, IIvx use the "Brazil" framebuffer (which is
+			   very much like the V8, it seems, and probably uses
+			   the same DAC) */
+		case MAC_MODEL_IIVI:
+		case MAC_MODEL_IIVX:
+		case MAC_MODEL_P600:
+			strcpy( fb_info.modename, "Brazil built-in" );
+			macfb_setpalette = v8_brazil_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+		
+			/* LC III (and friends) use the Sonora framebuffer */
+			/* Incidentally this is also used in the non-AV models
+			   of the x100 PowerMacs */
+			/* These do in fact seem to use the same DAC interface
+			   as the LC II. */
+		case MAC_MODEL_LCIII:
+		case MAC_MODEL_P520:
+		case MAC_MODEL_P550:
+		case MAC_MODEL_P460:
+			macfb_setpalette = v8_brazil_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcpy( fb_info.modename, "Sonora built-in" );
+			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+
+			/* IIci and IIsi use the infamous RBV chip
+                           (the IIsi is just a rebadged and crippled
+                           IIci in a different case, BTW) */
+		case MAC_MODEL_IICI:
+		case MAC_MODEL_IISI:
+			macfb_setpalette = rbv_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcpy( fb_info.modename, "RBV built-in" );
+			rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
+			break;
+
+			/* AVs use the Civic framebuffer */
+		case MAC_MODEL_Q840:
+		case MAC_MODEL_C660:
+			macfb_setpalette = civic_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcpy( fb_info.modename, "Civic built-in" );
+			civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
+			break;
+
+		
+			/* Write a setpalette function for your machine, then
+			   you can add something similar here.  These are
+			   grouped by classes of video chipsets.  Some of this
+			   information is from the VideoToolbox "Bugs" web
+			   page at
+			   http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */
+
+			/* Assorted weirdos */
+			/* We think this may be like the LC II */
+		case MAC_MODEL_LC:
+			if (vidtest) {
+				macfb_setpalette = v8_brazil_setpalette;
+				macfb_defined.activate = FB_ACTIVATE_NOW;
+				v8_brazil_cmap_regs =
+					ioremap(DAC_BASE, 0x1000);
+			}
+			strcpy( fb_info.modename, "LC built-in" );
+			break;
+			/* We think this may be like the LC II */
+		case MAC_MODEL_CCL:
+			if (vidtest) {
+				macfb_setpalette = v8_brazil_setpalette;
+				macfb_defined.activate = FB_ACTIVATE_NOW;
+				v8_brazil_cmap_regs =
+					ioremap(DAC_BASE, 0x1000);
+			}
+			strcpy( fb_info.modename, "Color Classic built-in" );
+			break;
+
+			/* And we *do* mean "weirdos" */
+		case MAC_MODEL_TV:
+			strcpy( fb_info.modename, "Mac TV built-in" );
+			break;
+
+			/* These don't have colour, so no need to worry */
+		case MAC_MODEL_SE30:
+		case MAC_MODEL_CLII:
+			strcpy( fb_info.modename, "Monochrome built-in" );
+			break;
+
+			/* Powerbooks are particularly difficult.  Many of
+			   them have separate framebuffers for external and
+			   internal video, which is admittedly pretty cool,
+			   but will be a bit of a headache to support here.
+			   Also, many of them are grayscale, and we don't
+			   really support that. */
+
+		case MAC_MODEL_PB140:
+		case MAC_MODEL_PB145:
+		case MAC_MODEL_PB170:
+			strcpy( fb_info.modename, "DDC built-in" );
+			break;
+
+			/* Internal is GSC, External (if present) is ViSC */
+		case MAC_MODEL_PB150:	/* no external video */
+		case MAC_MODEL_PB160:
+		case MAC_MODEL_PB165:
+		case MAC_MODEL_PB180:
+		case MAC_MODEL_PB210:
+		case MAC_MODEL_PB230:
+			strcpy( fb_info.modename, "GSC built-in" );
+			break;
+
+			/* Internal is TIM, External is ViSC */
+		case MAC_MODEL_PB165C:
+		case MAC_MODEL_PB180C:
+			strcpy( fb_info.modename, "TIM built-in" );
+			break;
+
+			/* Internal is CSC, External is Keystone+Ariel. */
+		case MAC_MODEL_PB190:	/* external video is optional */
+		case MAC_MODEL_PB520:
+		case MAC_MODEL_PB250:
+		case MAC_MODEL_PB270C:
+		case MAC_MODEL_PB280:
+		case MAC_MODEL_PB280C:
+			macfb_setpalette = csc_setpalette;
+			macfb_defined.activate = FB_ACTIVATE_NOW;
+			strcpy( fb_info.modename, "CSC built-in" );
+			csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
+			break;
+		
+		default:
+			strcpy( fb_info.modename, "Unknown/Unsupported built-in" );
+			break;
+		}
+	
+	fb_info.changevar  = NULL;
+	fb_info.node       = -1;
+	fb_info.fbops      = &macfb_ops;
+	fb_info.disp       = &disp;
+	fb_info.switch_con = &macfb_switch;
+	fb_info.updatevar  = &macfb_update_var;
+	fb_info.blank      = &macfb_blank;
+	fb_info.flags      = FBINFO_FLAG_DEFAULT;
+	macfb_set_disp(-1);
+	do_install_cmap(0, &fb_info);
+	
+	if (register_framebuffer(&fb_info) < 0)
+		return;
 
-#if 0
-/*
- * These two auxiliary debug functions should go away ASAP. Only usage: 
- * before the console output is up (after head.S come some other crucial
- * setup routines :-) 
- *
- * Now in debug.c ...
- */
-#endif
+	printk("fb%d: %s frame buffer device\n",
+	       GET_FB_IDX(fb_info.node), fb_info.modename);
+}
diff -u --recursive --new-file v2.3.44/linux/drivers/video/sun3fb.c linux/drivers/video/sun3fb.c
--- v2.3.44/linux/drivers/video/sun3fb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/sun3fb.c	Sun Feb 13 11:21:43 2000
@@ -0,0 +1,729 @@
+/*
+ *  linux/drivers/video/sun3fb.c -- Frame buffer driver for Sun3
+ *
+ * (C) 1998 Thomas Bogendoerfer
+ *
+ * This driver is bases on sbusfb.c, which is
+ *
+ *	Copyright (C) 1998 Jakub Jelinek
+ *
+ *  This driver is partly based on the Open Firmware console driver
+ *
+ *	Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  and SPARC console subsystem
+ *
+ *      Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
+ *      Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
+ *      Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *      Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ *      Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *      Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>	/* io_remap_page_range() */
+
+#ifdef CONFIG_SUN3
+#include <asm/oplib.h>
+#endif
+#ifdef CONFIG_SUN3X
+#include <asm/sun3x.h>
+#endif
+#include <video/sbusfb.h>
+
+#define DEFAULT_CURSOR_BLINK_RATE       (2*HZ/5)
+
+#define CURSOR_SHAPE			1
+#define CURSOR_BLINK			2
+
+    /*
+     *  Interface used by the world
+     */
+
+int sun3fb_init(void);
+int sun3fb_setup(char *options);
+
+static int currcon;
+static char fontname[40] __initdata = { 0 };
+static int curblink __initdata = 1;
+
+static int sun3fb_open(struct fb_info *info, int user);
+static int sun3fb_release(struct fb_info *info, int user);
+static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			struct fb_info *info);
+static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int sun3fb_pan_display(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int sun3fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			    u_long arg, int con, struct fb_info *info);
+static void sun3fb_cursor(struct display *p, int mode, int x, int y);
+static void sun3fb_clear_margin(struct display *p, int s);
+			    
+
+    /*
+     *  Interface to the low level console driver
+     */
+
+static int sun3fbcon_switch(int con, struct fb_info *info);
+static int sun3fbcon_updatevar(int con, struct fb_info *info);
+static void sun3fbcon_blank(int blank, struct fb_info *info);
+
+
+    /*
+     *  Internal routines
+     */
+
+static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			    u_int *transp, struct fb_info *info);
+static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			    u_int transp, struct fb_info *info);
+static void do_install_cmap(int con, struct fb_info *info);
+
+static struct fb_ops sun3fb_ops = {
+	sun3fb_open, sun3fb_release, sun3fb_get_fix, sun3fb_get_var, sun3fb_set_var,
+	sun3fb_get_cmap, sun3fb_set_cmap, sun3fb_pan_display, sun3fb_ioctl
+};
+
+
+    /*
+     *  Open/Release the frame buffer device
+     */
+
+static int sun3fb_open(struct fb_info *info, int user)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int sun3fb_release(struct fb_info *info, int user)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static void sun3fb_clear_margin(struct display *p, int s)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+	if (fb->switch_from_graph)
+		(*fb->switch_from_graph)(fb);
+	if (fb->fill) {
+		unsigned short rects [16];
+
+		rects [0] = 0;
+		rects [1] = 0;
+		rects [2] = fb->var.xres_virtual;
+		rects [3] = fb->y_margin;
+		rects [4] = 0;
+		rects [5] = fb->y_margin;
+		rects [6] = fb->x_margin;
+		rects [7] = fb->var.yres_virtual;
+		rects [8] = fb->var.xres_virtual - fb->x_margin;
+		rects [9] = fb->y_margin;
+		rects [10] = fb->var.xres_virtual;
+		rects [11] = fb->var.yres_virtual;
+		rects [12] = fb->x_margin;
+		rects [13] = fb->var.yres_virtual - fb->y_margin;
+		rects [14] = fb->var.xres_virtual - fb->x_margin;
+		rects [15] = fb->var.yres_virtual;
+		(*fb->fill)(fb, p, s, 4, rects);
+	} else {
+		unsigned char *fb_base = p->screen_base, *q;
+		int skip_bytes = fb->y_margin * fb->var.xres_virtual;
+		int scr_size = fb->var.xres_virtual * fb->var.yres_virtual;
+		int h, he, incr, size;
+
+		he = fb->var.yres;
+		if (fb->var.bits_per_pixel == 1) {
+			fb_base -= (skip_bytes + fb->x_margin) / 8;
+			skip_bytes /= 8;
+			scr_size /= 8;
+			mymemset (fb_base, skip_bytes - fb->x_margin / 8);
+			mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
+			incr = fb->var.xres_virtual / 8;
+			size = fb->x_margin / 8 * 2;
+			for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
+			     h <= he; q += incr, h++)
+				mymemset (q, size);
+		} else {
+			fb_base -= (skip_bytes + fb->x_margin);
+			memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+			memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
+			incr = fb->var.xres_virtual;
+			size = fb->x_margin * 2;
+			for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
+			     h <= he; q += incr, h++)
+				memset (q, attr_bgcol(p,s), size);
+		}
+	}
+}
+
+static void sun3fb_disp_setup(struct display *p)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+	if (fb->setup)
+		fb->setup(p);	
+	sun3fb_clear_margin(p, 0);
+}
+
+    /*
+     *  Get the Fixed Part of the Display
+     */
+
+static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			  struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo));
+	return 0;
+}
+
+    /*
+     *  Get the User Defined Part of the Display
+     */
+
+static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
+	return 0;
+}
+
+    /*
+     *  Set the User Defined Part of the Display
+     */
+
+static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	if (var->xres > fb->var.xres || var->yres > fb->var.yres ||
+	    var->xres_virtual > fb->var.xres_virtual ||
+	    var->yres_virtual > fb->var.yres_virtual ||
+	    var->bits_per_pixel != fb->var.bits_per_pixel ||
+	    var->nonstd ||
+	    (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+	memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
+	return 0;
+}
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int sun3fb_pan_display(struct fb_var_screeninfo *var, int con,
+			      struct fb_info *info)
+{
+	if (var->xoffset || var->yoffset)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+    /*
+     *  Hardware cursor
+     */
+     
+static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
+
+static void
+sun3fb_cursor_timer_handler(unsigned long dev_addr)
+{
+	struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
+        
+	if (!fb->setcursor) return;
+                                
+	if (fb->cursor.mode & CURSOR_BLINK) {
+		fb->cursor.enable ^= 1;
+		fb->setcursor(fb);
+	}
+	
+	fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
+	add_timer(&fb->cursor.timer);
+}
+
+static void sun3fb_cursor(struct display *p, int mode, int x, int y)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+	
+	switch (mode) {
+	case CM_ERASE:
+		fb->cursor.mode &= ~CURSOR_BLINK;
+		fb->cursor.enable = 0;
+		(*fb->setcursor)(fb);
+		break;
+				  
+	case CM_MOVE:
+	case CM_DRAW:
+		if (fb->cursor.mode & CURSOR_SHAPE) {
+			fb->cursor.size.fbx = fontwidth(p);
+			fb->cursor.size.fby = fontheight(p);
+			fb->cursor.chot.fbx = 0;
+			fb->cursor.chot.fby = 0;
+			fb->cursor.enable = 1;
+			memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
+			fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
+			fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
+			fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
+			fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
+			(*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
+			(*fb->setcurshape) (fb);
+		}
+		fb->cursor.mode = CURSOR_BLINK;
+		if (fontwidthlog(p))
+			fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
+		else
+			fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
+		if (fontheightlog(p))
+			fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
+		else
+			fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
+		(*fb->setcursor)(fb);
+		break;
+	}
+}
+
+    /*
+     *  Get the Colormap
+     */
+
+static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	if (con == currcon) /* current console? */
+		return fb_get_cmap(cmap, kspc, sun3fb_getcolreg, info);
+	else if (fb_display[con].cmap.len) /* non default colormap? */
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
+	return 0;
+}
+
+    /*
+     *  Set the Colormap
+     */
+
+static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			 struct fb_info *info)
+{
+	int err;
+
+	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
+		if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<<fb_display[con].var.bits_per_pixel, 0)))
+			return err;
+	}
+	if (con == currcon) {			/* current console? */
+		err = fb_set_cmap(cmap, kspc, sun3fb_setcolreg, info);
+		if (!err) {
+			struct fb_info_sbusfb *fb = sbusfbinfo(info);
+			
+			if (fb->loadcmap)
+				(*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
+		}
+		return err;
+	} else
+		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	return 0;
+}
+
+static int sun3fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			u_long arg, int con, struct fb_info *info)
+{
+	return -EINVAL;
+}
+
+    /*
+     *  Setup: parse used options
+     */
+
+__initfunc(void sun3fb_setup(char *options))
+{
+	char *p;
+	
+	for (p = options;;) {
+		if (!strncmp(p, "font=", 5)) {
+			int i;
+			
+			for (i = 0; i < sizeof(fontname) - 1; i++)
+				if (p[i+5] == ' ' || !p[i+5])
+					break;
+			memcpy(fontname, p+5, i);
+			fontname[i] = 0;
+		} else if (!strncmp(p, "noblink", 7))
+			curblink = 0;
+		while (*p && *p != ' ' && *p != ',') p++;
+		if (*p != ',') break;
+		p++;
+	}
+
+	return 0;
+}
+
+static int sun3fbcon_switch(int con, struct fb_info *info)
+{
+	int x_margin, y_margin;
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+	int lastconsole;
+    
+	/* Do we have to save the colormap? */
+	if (fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap, 1, sun3fb_getcolreg, info);
+
+	if (info->display_fg) {
+		lastconsole = info->display_fg->vc_num;
+		if (lastconsole != con && 
+		    (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
+		     fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
+			fb->cursor.mode |= CURSOR_SHAPE;
+	}
+	x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
+	y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
+	if (fb->margins)
+		fb->margins(fb, &fb_display[con], x_margin, y_margin);
+	if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
+		fb->x_margin = x_margin; fb->y_margin = y_margin;
+		sun3fb_clear_margin(&fb_display[con], 0);
+	}
+	currcon = con;
+	/* Install new colormap */
+	do_install_cmap(con, info);
+	return 0;
+}
+
+    /*
+     *  Update the `var' structure (called by fbcon.c)
+     */
+
+static int sun3fbcon_updatevar(int con, struct fb_info *info)
+{
+	/* Nothing */
+	return 0;
+}
+
+    /*
+     *  Blank the display.
+     */
+
+static void sun3fbcon_blank(int blank, struct fb_info *info)
+{
+    struct fb_info_sbusfb *fb = sbusfbinfo(info);
+    
+    if (blank && fb->blank)
+    	return fb->blank(fb);
+    else if (!blank && fb->unblank)
+    	return fb->unblank(fb);
+}
+
+    /*
+     *  Read a single color register and split it into
+     *  colors/transparent. Return != 0 for invalid regno.
+     */
+
+static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			  u_int *transp, struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	if (!fb->color_map || regno > 255)
+		return 1;
+	*red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
+	*green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
+	*blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
+	*transp = 0;
+	return 0;
+}
+
+
+    /*
+     *  Set a single color register. The values supplied are already
+     *  rounded down to the hardware's capabilities (according to the
+     *  entries in the var structure). Return != 0 for invalid regno.
+     */
+
+static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			    u_int transp, struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+
+	if (!fb->color_map || regno > 255)
+		return 1;
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	fb->color_map CM(regno, 0) = red;
+	fb->color_map CM(regno, 1) = green;
+	fb->color_map CM(regno, 2) = blue;
+	return 0;
+}
+
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+	struct fb_info_sbusfb *fb = sbusfbinfo(info);
+	
+	if (con != currcon)
+		return;
+	if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, 1, sun3fb_setcolreg, info);
+	else
+		fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+			    1, sun3fb_setcolreg, info);
+	if (fb->loadcmap)
+		(*fb->loadcmap)(fb, &fb_display[con], 0, 256);
+}
+
+static int sun3fb_set_font(struct display *p, int width, int height)
+{
+	int w = p->var.xres_virtual, h = p->var.yres_virtual;
+	int depth = p->var.bits_per_pixel;
+	struct fb_info_sbusfb *fb = sbusfbinfod(p);
+	int x_margin, y_margin;
+	
+	if (depth > 8) depth = 8;
+	x_margin = (w % width) / 2;
+	y_margin = (h % height) / 2;
+
+	p->var.xres = w - 2*x_margin;
+	p->var.yres = h - 2*y_margin;
+	
+	fb->cursor.mode |= CURSOR_SHAPE;
+	
+	if (fb->margins)
+		fb->margins(fb, p, x_margin, y_margin);
+	if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
+		fb->x_margin = x_margin; fb->y_margin = y_margin;
+		sun3fb_clear_margin(p, 0);
+	}
+
+	return 1;
+}
+
+void sun3fb_palette(int enter)
+{
+	int i;
+	struct display *p;
+	
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		p = &fb_display[i];
+		if (p->dispsw && p->dispsw->setup == sun3fb_disp_setup &&
+		    p->fb_info->display_fg &&
+		    p->fb_info->display_fg->vc_num == i) {
+			struct fb_info_sbusfb *fb = sbusfbinfod(p);
+
+			if (fb->restore_palette) {
+				if (enter)
+					fb->restore_palette(fb);
+				else if (vt_cons[i]->vc_mode != KD_GRAPHICS)
+				         vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
+			}
+		}
+	}
+}
+
+    /*
+     *  Initialisation
+     */
+__initfunc(static void sun3fb_init_fb(int fbtype, unsigned long addr))
+{
+	static struct linux_sbus_device sdb;
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	struct display *disp;
+	struct fb_info_sbusfb *fb;
+	struct fbtype *type;
+	int linebytes, w, h, depth;
+	char *p = NULL;
+
+	fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
+	if (!fb)
+		return -ENOMEM;
+	
+	memset(fb, 0, sizeof(struct fb_info_sbusfb));
+	fix = &fb->fix;
+	var = &fb->var;
+	disp = &fb->disp;
+	type = &fb->type;
+	
+	sdb.reg_addrs[0].phys_addr = addr;
+	fb->sbdp = &sdb;
+
+	type->fb_type = fbtype;
+	
+	type->fb_height = h = 900;
+	type->fb_width  = w = 1152;
+sizechange:
+	type->fb_depth  = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
+	linebytes = w * depth / 8;
+	type->fb_size   = PAGE_ALIGN((linebytes) * h);
+	
+	fb->x_margin = (w & 7) / 2;
+	fb->y_margin = (h & 15) / 2;
+
+	var->xres_virtual = w;
+	var->yres_virtual = h;
+	var->xres = w - 2*fb->x_margin;
+	var->yres = h - 2*fb->y_margin;
+	
+	var->bits_per_pixel = depth;
+	var->height = var->width = -1;
+	var->pixclock = 10000;
+	var->vmode = FB_VMODE_NONINTERLACED;
+	var->red.length = var->green.length = var->blue.length = 8;
+
+	fix->line_length = linebytes;
+	fix->smem_len = type->fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	
+	fb->info.node = -1;
+	fb->info.fbops = &sun3fb_ops;
+	fb->info.disp = disp;
+	strcpy(fb->info.fontname, fontname);
+	fb->info.changevar = NULL;
+	fb->info.switch_con = &sun3fbcon_switch;
+	fb->info.updatevar = &sun3fbcon_updatevar;
+	fb->info.blank = &sun3fbcon_blank;
+	fb->info.flags = FBINFO_FLAG_DEFAULT;
+	
+	fb->cursor.hwsize.fbx = 32;
+	fb->cursor.hwsize.fby = 32;
+	
+	if (depth > 1 && !fb->color_map)
+		fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
+		
+	switch(fbtype) {
+#ifdef CONFIG_FB_CGSIX
+	case FBTYPE_SUNFAST_COLOR:
+		p = cgsixfb_init(fb); break;
+#endif
+#ifdef CONFIG_FB_BWTWO
+	case FBTYPE_SUN2BW:
+		p = bwtwofb_init(fb); break;
+#endif
+	}
+	fix->smem_start = fb->disp.screen_base;
+	
+	if (!p) {
+		kfree(fb);
+		-ENODEV;
+	}
+	
+	if (p == SBUSFBINIT_SIZECHANGE)
+		goto sizechange;
+
+	disp->dispsw = &fb->dispsw;
+	if (fb->setcursor) {
+		fb->dispsw.cursor = sun3fb_cursor;
+		if (curblink) {
+			fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+			init_timer(&fb->cursor.timer);
+			fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
+			fb->cursor.timer.data = (unsigned long)fb;
+			fb->cursor.timer.function = sun3fb_cursor_timer_handler;
+			add_timer(&fb->cursor.timer);
+		}
+	}
+	fb->cursor.mode = CURSOR_SHAPE;
+	fb->dispsw.set_font = sun3fb_set_font;
+	fb->setup = fb->dispsw.setup;
+	fb->dispsw.setup = sun3fb_disp_setup;
+	fb->dispsw.clear_margins = NULL;
+
+	disp->var = *var;
+	disp->visual = fix->visual;
+	disp->type = fix->type;
+	disp->type_aux = fix->type_aux;
+	disp->line_length = fix->line_length;
+	
+	if (fb->blank)
+		disp->can_soft_blank = 1;
+
+	sun3fb_set_var(var, -1, &fb->info);
+
+	if (register_framebuffer(&fb->info) < 0) {
+		kfree(fb);
+		return -EINVAL;
+	}
+	printk("fb%d: %s\n", GET_FB_IDX(fb->info.node), p);
+
+	return 0;
+}
+
+
+__initfunc(int sun3fb_init(void))
+{
+	extern int con_is_present(void);
+	unsigned long addr;
+	char p4id;
+	
+	if (!con_is_present()) return;
+	printk("sun3fb_init()\n");
+#ifdef CONFIG_SUN3
+	addr = 0xfe20000;
+        switch(*(romvec->pv_fbtype))
+        {
+		case FBTYPE_SUN2BW:
+			return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+		case FBTYPE_SUN3COLOR:
+			printk("cg3 detected but not supported\n");
+			return -EINVAL;
+	}
+#else
+	addr = SUN3X_VIDEO_BASE;
+	p4id = *(char *)SUN3X_VIDEO_P4ID;
+
+	p4id = (p4id == 0x45) ? p4id : (p4id & 0xf0);
+	switch (p4id) {
+		case 0x00:
+			return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
+#if 0 /* not yet */
+		case 0x40:
+			sun3fb_init_fb(FBTYPE_SUN4COLOR, addr);
+			break;
+		case 0x45:
+			sun3fb_init_fb(FBTYPE_SUN8COLOR, addr);
+			break;
+#endif
+		case 0x60:
+			return sun3fb_init_fb(FBTYPE_SUNFAST_COLOR, addr);
+	}
+#endif			
+}
diff -u --recursive --new-file v2.3.44/linux/fs/Config.in linux/fs/Config.in
--- v2.3.44/linux/fs/Config.in	Thu Feb 10 17:11:16 2000
+++ linux/fs/Config.in	Sun Feb 13 12:40:41 2000
@@ -60,7 +60,9 @@
 dep_bool '  SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL
 
 tristate 'UDF filesystem support (read only)' CONFIG_UDF_FS
-dep_bool '  UDF write support (DANGEROUS)' CONFIG_UDF_RW $CONFIG_UDF_FS $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool '  UDF write support (DANGEROUS)' CONFIG_UDF_RW
+fi
 
 tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
 dep_bool '  UFS filesystem write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
diff -u --recursive --new-file v2.3.44/linux/fs/adfs/file.c linux/fs/adfs/file.c
--- v2.3.44/linux/fs/adfs/file.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/adfs/file.c	Sun Feb 13 10:45:13 2000
@@ -44,4 +44,8 @@
 
 struct inode_operations adfs_file_inode_operations = {
 	&adfs_file_operations,	/* default file operations */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+	readpage:	generic_readpage,
+	bmap:		adfs_bmap,
+#endif
 };
diff -u --recursive --new-file v2.3.44/linux/fs/adfs/inode.c linux/fs/adfs/inode.c
--- v2.3.44/linux/fs/adfs/inode.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/adfs/inode.c	Sun Feb 13 13:04:48 2000
@@ -48,30 +48,36 @@
 abort_toobig:
 	return 0;
 }
+
 static int adfs_writepage(struct dentry *dentry, struct page *page)
 {
-	return block_write_full_page(page,adfs_get_block);
+	return block_write_full_page(page, adfs_get_block);
 }
+
 static int adfs_readpage(struct dentry *dentry, struct page *page)
 {
-	return block_read_full_page(page,adfs_get_block);
+	return block_read_full_page(page, adfs_get_block);
 }
-static int adfs_prepare_write(struct page *page, unsigned from, unsigned to)
+
+static int adfs_prepare_write(struct page *page, unsigned int from, unsigned int to)
 {
-	return cont_prepare_write(page,from,to,adfs_get_block,
-		&((struct inode*)page->mapping->host)->u.adfs_i.mmu_private);
+	return cont_prepare_write(page, from, to, adfs_get_block,
+		&((struct inode *)page->mapping->host)->u.adfs_i.mmu_private);
 }
+
 static int _adfs_bmap(struct address_space *mapping, long block)
 {
-	return generic_block_bmap(mapping,block,adfs_get_block);
+	return generic_block_bmap(mapping, block, adfs_get_block);
 }
-struct address_space_operations adfs_aops = {
-	readpage: adfs_readpage,
-	writepage: adfs_writepage,
-	prepare_write: adfs_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: _adfs_bmap
+
+static struct address_space_operations adfs_aops = {
+	readpage:	adfs_readpage,
+	writepage:	adfs_writepage,
+	prepare_write:	adfs_prepare_write,
+	commit_write:	generic_commit_write,
+	bmap:		_adfs_bmap
 };
+
 #else
 int adfs_bmap(struct inode *inode, int block)
 {
@@ -280,7 +286,7 @@
 	if (S_ISDIR(inode->i_mode))
 		inode->i_op	= &adfs_dir_inode_operations;
 	else if (S_ISREG(inode->i_mode)) {
-		inode->i_op	 = &adfs_file_inode_operations;
+		inode->i_op	= &adfs_file_inode_operations;
 		inode->i_mapping->a_ops = &adfs_aops;
 		inode->u.adfs_i.mmu_private = inode->i_size;
 	}
@@ -328,8 +334,10 @@
 	if (error)
 		goto out;
 
-	if (ia_valid & ATTR_SIZE)
+	if (ia_valid & ATTR_SIZE) {
 		inode->i_size = attr->ia_size;
+		vmtruncate(inode, attr->ia_size);
+	}
 	if (ia_valid & ATTR_MTIME) {
 		inode->i_mtime = attr->ia_mtime;
 		adfs_unix2adfs_time(inode, attr->ia_mtime);
diff -u --recursive --new-file v2.3.44/linux/fs/adfs/map.c linux/fs/adfs/map.c
--- v2.3.44/linux/fs/adfs/map.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/adfs/map.c	Sun Feb 13 10:45:13 2000
@@ -44,7 +44,6 @@
 		/*
 		 * get fragment id
 		 */
-		//asm("@ get fragment id start");
 		{
 			unsigned long v2;
 			unsigned int tmp;
@@ -60,14 +59,12 @@
 
 			frag &= idmask;
 		}
-		//asm("@ get fragment id end");
 
 		mapptr = start + idlen;
 
 		/*
 		 * find end of fragment
 		 */
-		//asm("@ find end of fragment start");
 		{
 			unsigned long v2;
 
@@ -79,7 +76,6 @@
 
 			mapptr += 1 + ffz(~v2);
 		}
-		//asm("@ find end of fragment end");
 
 		if (frag == frag_id)
 			goto found;
@@ -122,7 +118,6 @@
 	/*
 	 * get fragment id
 	 */
-	//asm("@ get fragment id start");
 	{
 		unsigned long v2;
 		unsigned int tmp;
@@ -138,7 +133,6 @@
 
 		frag &= idmask;
 	}
-	//asm("@ get fragment id end");
 
 	/*
 	 * If the freelink is null, then no free fragments
@@ -153,7 +147,6 @@
 		/*
 		 * get fragment id
 		 */
-		//asm("@ get fragment id start");
 		{
 			unsigned long v2;
 			unsigned int tmp;
@@ -169,14 +162,12 @@
 
 			frag &= idmask;
 		}
-		//asm("@ get fragment id end");
 
 		mapptr = start + idlen;
 
 		/*
 		 * find end of fragment
 		 */
-		//asm("@ find end of fragment start");
 		{
 			unsigned long v2;
 
@@ -188,7 +179,6 @@
 
 			mapptr += 1 + ffz(~v2);
 		}
-		//asm("@ find end of fragment end");
 
 		total += mapptr - start;
 	} while (frag >= idlen + 1);
diff -u --recursive --new-file v2.3.44/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.3.44/linux/fs/affs/inode.c	Thu Feb 10 17:11:16 2000
+++ linux/fs/affs/inode.c	Sun Feb 13 13:04:48 2000
@@ -249,9 +249,8 @@
 	if (attr->ia_valid & ATTR_MODE)
 		inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
 
-	inode_setattr(inode, attr);
-	mark_inode_dirty(inode);
 	error = 0;
+	inode_setattr(inode, attr);
 out:
 	return error;
 }
diff -u --recursive --new-file v2.3.44/linux/fs/attr.c linux/fs/attr.c
--- v2.3.44/linux/fs/attr.c	Fri Nov 13 10:07:26 1998
+++ linux/fs/attr.c	Sun Feb 13 13:04:48 2000
@@ -62,8 +62,10 @@
 		inode->i_uid = attr->ia_uid;
 	if (ia_valid & ATTR_GID)
 		inode->i_gid = attr->ia_gid;
-	if (ia_valid & ATTR_SIZE)
+	if (ia_valid & ATTR_SIZE) {
 		inode->i_size = attr->ia_size;
+		vmtruncate(inode, attr->ia_size);
+	}
 	if (ia_valid & ATTR_ATIME)
 		inode->i_atime = attr->ia_atime;
 	if (ia_valid & ATTR_MTIME)
diff -u --recursive --new-file v2.3.44/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.3.44/linux/fs/fat/cache.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/fat/cache.c	Sun Feb 13 13:04:48 2000
@@ -283,7 +283,7 @@
 			return 0;
 		return sector+sb->dir_start;
 	}
-	if (sector >= MSDOS_I(inode)->mmu_private>>9)
+	if (sector >= (MSDOS_I(inode)->mmu_private+511)>>9)
 		return 0;
 	cluster = sector/sb->cluster_size;
 	offset = sector % sb->cluster_size;
diff -u --recursive --new-file v2.3.44/linux/fs/hpfs/namei.c linux/fs/hpfs/namei.c
--- v2.3.44/linux/fs/hpfs/namei.c	Thu Feb 10 17:11:17 2000
+++ linux/fs/hpfs/namei.c	Sun Feb 13 10:33:23 2000
@@ -329,21 +329,18 @@
 		d_delete(dentry);
 	} else {	/* no space for deleting, try to truncate file */
 		struct iattr newattrs;
+		int err;
 		hpfs_unlock_2inodes(dir, inode);
 		if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret;
 		/*printk("HPFS: truncating file before delete.\n");*/
-		down(&inode->i_sem);	/* do_truncate should be called here, but it's */
-		newattrs.ia_size = 0;	/* not exported */
+		down(&inode->i_sem);
+		newattrs.ia_size = 0;
 		newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-		if (notify_change(dentry, &newattrs)) {
-			up(&inode->i_sem);
-			put_write_access(inode);
-			goto ret;
-		}
-		vmtruncate(inode, 0);
-		if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode);
+		err = notify_change(dentry, &newattrs);
 		up(&inode->i_sem);
 		put_write_access(inode);
+		if (err)
+			goto ret;
 		rep = 1;
 		goto again;
 	}
diff -u --recursive --new-file v2.3.44/linux/fs/inode.c linux/fs/inode.c
--- v2.3.44/linux/fs/inode.c	Sat Feb 12 11:22:11 2000
+++ linux/fs/inode.c	Sun Feb 13 18:20:21 2000
@@ -94,7 +94,7 @@
 		INIT_LIST_HEAD(&inode->i_data.pages);
 		INIT_LIST_HEAD(&inode->i_dentry);
 		sema_init(&inode->i_sem, 1);
-		spin_lock_init(&inode->i_shared_lock);
+		spin_lock_init(&inode->i_data.i_shared_lock);
 	}
 }
 
@@ -280,7 +280,7 @@
 
 		inode = list_entry(inode_entry, struct inode, i_list);
 		if (inode->i_data.nrpages)
-			truncate_inode_pages(inode, 0);
+			truncate_inode_pages(&inode->i_data, 0);
 		clear_inode(inode);
 		destroy_inode(inode);
 	}
@@ -673,7 +673,7 @@
 					void (*delete)(struct inode *) = op->delete_inode;
 					spin_unlock(&inode_lock);
 					if (inode->i_data.nrpages)
-						truncate_inode_pages(inode, 0);
+						truncate_inode_pages(&inode->i_data, 0);
 					delete(inode);
 					spin_lock(&inode_lock);
 				}
diff -u --recursive --new-file v2.3.44/linux/fs/locks.c linux/fs/locks.c
--- v2.3.44/linux/fs/locks.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/locks.c	Sun Feb 13 18:20:21 2000
@@ -416,15 +416,16 @@
 	if (IS_MANDLOCK(inode) &&
 	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
 		struct vm_area_struct *vma;
-		spin_lock(&inode->i_shared_lock);
-		for(vma = inode->i_mmap;vma;vma = vma->vm_next_share) {
+		struct address_space *mapping = inode->i_mapping;
+		spin_lock(&mapping->i_shared_lock);
+		for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
 			if (!(vma->vm_flags & VM_MAYSHARE))
 				continue;
-			spin_unlock(&inode->i_shared_lock);
+			spin_unlock(&mapping->i_shared_lock);
 			error = -EAGAIN;
 			goto out_putf;
 		}
-		spin_unlock(&inode->i_shared_lock);
+		spin_unlock(&mapping->i_shared_lock);
 	}
 
 	error = -EINVAL;
diff -u --recursive --new-file v2.3.44/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.3.44/linux/fs/ncpfs/inode.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/ncpfs/inode.c	Sun Feb 13 13:04:48 2000
@@ -693,6 +693,8 @@
 		/* According to ndir, the changes only take effect after
 		   closing the file */
 		result = ncp_make_closed(inode);
+		if (!result)
+			vmtruncate(inode, attr->ia_size);
 	}
 out:
 	return result;
diff -u --recursive --new-file v2.3.44/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.3.44/linux/fs/nfs/inode.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/nfs/inode.c	Sun Feb 13 13:04:48 2000
@@ -689,6 +689,8 @@
 	if (attr->ia_valid & ATTR_MTIME)
 		inode->i_mtime = fattr.mtime.seconds;
 	error = nfs_refresh_inode(inode, &fattr);
+	if (!error && (attr->ia_valid & ATTR_SIZE))
+		vmtruncate(inode, attr->ia_size);
 out:
 	return error;
 }
diff -u --recursive --new-file v2.3.44/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.3.44/linux/fs/nfsd/nfsfh.c	Fri Jan 28 15:09:09 2000
+++ linux/fs/nfsd/nfsfh.c	Sun Feb 13 10:30:54 2000
@@ -301,7 +301,7 @@
 	struct dentry *dentry, *result = NULL;
 	struct dentry *tmp;
 	int  found =0;
-	u32 err;
+	long err;
 	/* This semaphore is needed to make sure that only one unconnected (free)
 	 * dcache path ever exists, as otherwise two partial paths might get
 	 * joined together, which would be very confusing.
diff -u --recursive --new-file v2.3.44/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.44/linux/fs/nfsd/vfs.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/nfsd/vfs.c	Sun Feb 13 10:33:23 2000
@@ -310,11 +310,6 @@
 	if (iap->ia_valid & ATTR_SIZE) {
 		fh_lock(fhp);
 		err = notify_change(dentry, iap);
-		if (!err) {
-			vmtruncate(inode,iap->ia_size);		
-			if (inode->i_op && inode->i_op->truncate)
-				inode->i_op->truncate(inode);
-		}
 		fh_unlock(fhp);
 		put_write_access(inode);
 	}
@@ -1082,11 +1077,6 @@
 		cap_clear(current->cap_effective);
 	}
 	err = notify_change(dentry, &newattrs);
-	if (!err) {
-		vmtruncate(inode, size);
-		if (inode->i_op && inode->i_op->truncate)
-			inode->i_op->truncate(inode);
-	}
 	if (current->fsuid != 0)
 		current->cap_effective = saved_cap;
 	put_write_access(inode);
diff -u --recursive --new-file v2.3.44/linux/fs/open.c linux/fs/open.c
--- v2.3.44/linux/fs/open.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/open.c	Sun Feb 13 10:33:23 2000
@@ -69,12 +69,6 @@
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 	error = notify_change(dentry, &newattrs);
-	if (!error) {
-		/* truncate virtual mappings of this file */
-		vmtruncate(inode, length);
-		if (inode->i_op && inode->i_op->truncate)
-			inode->i_op->truncate(inode);
-	}
 	up(&inode->i_sem);
 	return error;
 }
diff -u --recursive --new-file v2.3.44/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.3.44/linux/fs/smbfs/inode.c	Thu Feb 10 17:11:18 2000
+++ linux/fs/smbfs/inode.c	Sun Feb 13 18:20:21 2000
@@ -489,7 +489,8 @@
 		 */
 		if (attr->ia_size < inode->i_size)
 		{
-			truncate_inode_pages(inode, attr->ia_size);
+			/* must die */
+			truncate_inode_pages(inode->i_mapping, attr->ia_size);
 			inode->i_size = attr->ia_size;
 		}
 		refresh = 1;
@@ -562,6 +563,8 @@
 out:
 	if (refresh)
 		smb_refresh_inode(dentry);
+	if (!error && (attr->ia_valid & ATTR_SIZE))
+		vmtruncate(inode, attr->ia_size);
 	return error;
 }
 
diff -u --recursive --new-file v2.3.44/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.3.44/linux/fs/umsdos/inode.c	Thu Feb 10 17:11:19 2000
+++ linux/fs/umsdos/inode.c	Sun Feb 13 18:20:21 2000
@@ -170,11 +170,19 @@
 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *dir = dentry->d_parent->d_inode;
+	struct inode *inode = dentry->d_inode;
 	int ret;
 
+	ret = inode_change_ok (inode, attr);
+	if (ret)
+		goto out;
+
 	down(&dir->i_sem);
 	ret = umsdos_notify_change_locked(dentry, attr);
 	up(&dir->i_sem);
+	if (ret == 0)
+		inode_setattr (inode, attr);
+out:
 	return ret;
 }
 
@@ -185,20 +193,13 @@
 {
 	struct inode *inode = dentry->d_inode;
 	struct dentry *demd;
-	int ret;
+	int ret = 0;
 	struct file filp;
 	struct umsdos_dirent entry;
 
 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
 
-	ret = inode_change_ok (inode, attr);
-	if (ret) {
-printk("UMSDOS_notify_change: %s/%s change not OK, ret=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, ret);
-		goto out;
-	}
-
 	if (inode->i_nlink == 0)
 		goto out;
 	if (inode->i_ino == UMSDOS_ROOT_INO)
@@ -276,8 +277,6 @@
 out_dput:
 	dput(demd);
 out:
-	if (ret == 0)
-		inode_setattr (inode, attr);
 	return ret;
 }
 
diff -u --recursive --new-file v2.3.44/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.3.44/linux/fs/umsdos/namei.c	Tue Dec 14 01:27:24 1999
+++ linux/fs/umsdos/namei.c	Sun Feb 13 13:04:48 2000
@@ -731,6 +731,8 @@
 oldinode->i_ino, oldinode->i_nlink));
 		newattrs.ia_valid = 0;
 		ret = umsdos_notify_change_locked(olddentry, &newattrs);
+		if (ret == 0)
+			mark_inode_dirty(olddentry->d_inode);
 	}
 	if (olddir != dir)
 		up(&olddir->i_sem);
@@ -1069,6 +1071,8 @@
 		inode->i_nlink--;
 		newattrs.ia_valid = 0;
 		ret = umsdos_notify_change_locked(link, &newattrs);
+		if (!ret)
+			mark_inode_dirty(link->d_inode);
 	}
 
 out_cleanup:
diff -u --recursive --new-file v2.3.44/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.3.44/linux/include/asm-alpha/pgtable.h	Sat Feb 12 11:22:11 2000
+++ linux/include/asm-alpha/pgtable.h	Sun Feb 13 10:30:57 2000
@@ -249,8 +249,9 @@
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* to find an entry in a page-table-directory. */
-#define __pgd_offset(address)	((address >> PGDIR_SHIFT) & PTRS_PER_PGD)
-#define pgd_offset(mm, address)	((mm)->pgd+__pgd_offset(address))
+#define pgd_index(address)	((address >> PGDIR_SHIFT) & PTRS_PER_PGD)
+#define __pgd_offset(address)	pgd_index(address)
+#define pgd_offset(mm, address)	((mm)->pgd+pgd_index(address))
 
 /* Find an entry in the second-level page table.. */
 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.3.44/linux/include/asm-arm/hardirq.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-arm/hardirq.h	Sun Feb 13 10:47:01 2000
@@ -9,7 +9,10 @@
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
  */
-#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+#define in_interrupt() ({ const int __cpu = smp_processor_id(); \
+	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
 
 #ifndef __SMP__
 
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.3.44/linux/include/asm-arm/io.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-arm/io.h	Sun Feb 13 10:47:01 2000
@@ -15,6 +15,7 @@
 #ifndef __ASM_ARM_IO_H
 #define __ASM_ARM_IO_H
 
+#include <linux/types.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/io.h>
 #include <asm/proc/io.h>
@@ -66,21 +67,31 @@
 /*
  * ioremap and friends
  */
-extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+extern void * __ioremap(unsigned long offset, size_t size, unsigned long flags);
 extern void __iounmap(void *addr);
 
 #define ioremap(off,sz)			__arch_ioremap((off),(sz),0)
 #define ioremap_nocache(off,sz)		__arch_ioremap((off),(sz),1)
 #define iounmap(_addr)			__iounmap(_addr)
 
+/*
+ * DMA-consistent mapping functions.  These allocate/free a region of
+ * uncached, unwrite-buffered mapped memory space for use with DMA
+ * devices.  This is the "generic" version.  The PCI specific version
+ * is in pci.h
+ */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
+extern void consistent_free(void *vaddr);
+extern void consistent_sync(void *vaddr, size_t size, int rw);
+
 extern void __readwrite_bug(const char *fn);
 
 /*
  * 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);
+extern void _memcpy_fromio(void *, unsigned long, size_t);
+extern void _memcpy_toio(unsigned long, const void *, size_t);
+extern void _memset_io(unsigned long, int, size_t);
 
 #define __raw_writeb(val,addr)		__arch_putb(val,addr)
 #define __raw_writew(val,addr)		__arch_putw(val,addr)
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/md.h linux/include/asm-arm/md.h
--- v2.3.44/linux/include/asm-arm/md.h	Thu Dec 17 09:05:43 1998
+++ linux/include/asm-arm/md.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/* $Id: md.h,v 1.1 1997/12/15 15:11:57 jj Exp $
- * md.h: High speed xor_block operation for RAID4/5 
- *
- */
- 
-#ifndef __ASM_MD_H
-#define __ASM_MD_H
-
-/* #define HAVE_ARCH_XORBLOCK */
-
-#define MD_XORBLOCK_ALIGNMENT	sizeof(long)
-
-#endif /* __ASM_MD_H */
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- v2.3.44/linux/include/asm-arm/pci.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/pci.h	Sun Feb 13 10:47:01 2000
@@ -3,5 +3,153 @@
 
 #define pcibios_assign_all_busses()	0
 
-#endif
+#define PCIBIOS_MIN_IO		0x8000
+#define PCIBIOS_MIN_MEM		0x40000000
+
+#ifdef __KERNEL__
+
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+struct pci_dev;
+
+/* Allocate and map kernel buffer using consistent mode DMA for a device.
+ * hwdev should be valid struct pci_dev pointer for PCI devices,
+ * NULL for PCI-like buses (ISA, EISA).
+ * Returns non-NULL cpu-view pointer to the buffer if successful and
+ * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
+ * is undefined.
+ */
+#define pci_alloc_consistent(hwdev,size,handle)		\
+	({						\
+		void *__ret;				\
+		int __gfp = GFP_KERNEL;			\
+							\
+		if ((hwdev) == NULL ||			\
+		    (hwdev)->dma_mask != 0xffffffff)	\
+			__gfp |= GFP_DMA;		\
+							\
+		__ret = consistent_alloc(__gfp, (size),	\
+					 (handle));	\
+		__ret;					\
+	})
+
+/* Free and unmap a consistent DMA buffer.
+ * cpu_addr is what was returned from pci_alloc_consistent,
+ * size must be the same as what as passed into pci_alloc_consistent,
+ * and likewise dma_addr must be the same as what *dma_addrp was set to.
+ *
+ * References to the memory and mappings associated with cpu_addr/dma_addr
+ * past this call are illegal.
+ */
+extern inline void
+pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+		    dma_addr_t dma_handle)
+{
+	consistent_free(vaddr);
+}
+
+/* Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+extern inline dma_addr_t
+pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size)
+{
+	consistent_sync(ptr, size, 3);
+	return virt_to_bus(ptr);
+}
+
+/* Unmap a single streaming mode DMA translation.  The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+extern inline void
+pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size)
+{
+	/* nothing to do */
+}
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+extern inline int
+pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+{
+	int i;
 
+	for (i = 0; i < nents; i++, sg++)
+		consistent_sync(sg->address, sg->length, 3);
+
+	return nents;
+}
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+extern inline void
+pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents)
+{
+	/* nothing to do */
+}
+
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+extern inline void
+pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size)
+{
+	consistent_sync(bus_to_virt(dma_handle), size, 3);
+}
+
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+extern inline void
+pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems)
+{
+	int i;
+
+	for (i = 0; i < nelems; i++, sg++)
+		consistent_sync(sg->address, sg->length, 3);
+}
+
+/* These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg)      (virt_to_bus((sg)->address))
+#define sg_dma_len(sg)          ((sg)->length)
+
+#endif /* __KERNEL__ */
+ 
+#endif
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.3.44/linux/include/asm-arm/pgtable.h	Tue Dec 14 01:27:24 1999
+++ linux/include/asm-arm/pgtable.h	Sun Feb 13 10:31:01 2000
@@ -122,9 +122,10 @@
 #define page_pte(page)		mk_pte(page, __pgprot(0))
 
 /* to find an entry in a page-table-directory */
-#define __pgd_offset(addr)	((addr) >> PGDIR_SHIFT)
+#define pgd_index(addr)		((addr) >> PGDIR_SHIFT)
+#define __pgd_offset(addr)	pgd_index(addr)
 
-#define pgd_offset(mm, addr)	((mm)->pgd+__pgd_offset(addr))
+#define pgd_offset(mm, addr)	((mm)->pgd+pgd_index(addr))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(addr)	pgd_offset(&init_mm, addr)
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/proc-armo/semaphore.h linux/include/asm-arm/proc-armo/semaphore.h
--- v2.3.44/linux/include/asm-arm/proc-armo/semaphore.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/proc-armo/semaphore.h	Sun Feb 13 10:47:01 2000
@@ -1,109 +1,75 @@
 /*
- * linux/include/asm-arm/proc-armo/semaphore.h
+ * linux/include/asm-arm/proc-armo/locks.h
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * Interrupt safe locking assembler.
  */
-#ifndef __ASM_PROC_SEMAPHORE_H
-#define __ASM_PROC_SEMAPHORE_H
+#ifndef __ASM_PROC_LOCKS_H
+#define __ASM_PROC_LOCKS_H
 
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down" is the actual routine that waits...
- */
-extern inline void down(struct semaphore * sem)
-{
-	__asm__ __volatile__ ("
-	@ atomic down operation
-	mov	r0, pc
-	orr	lr, r0, #0x08000000
-	teqp	lr, #0
-	ldr	lr, [%0]
-	and	r0, r0, #0x0c000003
-	subs	lr, lr, #1
-	str	lr, [%0]
-	orrmi	r0, r0, #0x80000000	@ set N
-	teqp	r0, #0
-	movmi	r0, %0
-	blmi	" SYMBOL_NAME_STR(__down_failed)
-		:
-		: "r" (sem)
-		: "r0", "lr", "cc");
-}
-
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down_interruptible" is the actual routine that waits...
- */
-extern inline int down_interruptible (struct semaphore * sem)
-{
-	int result;
-	__asm__ __volatile__ ("
-	@ atomic down operation
-	mov	r0, pc
-	orr	lr, r0, #0x08000000
-	teqp	lr, #0
-	ldr	lr, [%1]
-	and	r0, r0, #0x0c000003
-	subs	lr, lr, #1
-	str	lr, [%1]
-	orrmi	r0, r0, #0x80000000	@ set N
-	teqp	r0, #0
-	movmi	r0, %1
-	movpl	r0, #0
-	blmi	" SYMBOL_NAME_STR(__down_interruptible_failed) "
-	mov	%0, r0"
-		: "=r" (result)
-		: "r" (sem)
-		: "r0", "lr", "cc");
-	return result;
-}
+#define __down_op(ptr,fail)			\
+	({					\
+	__asm__ __volatile__ (			\
+	"@ atomic down operation\n"		\
+"	mov	r0, pc\n"			\
+"	orr	lr, r0, #0x08000000\n"		\
+"	teqp	lr, #0\n"			\
+"	ldr	lr, [%0]\n"			\
+"	and	r0, r0, #0x0c000003\n"		\
+"	subs	lr, lr, #1\n"			\
+"	str	lr, [%0]\n"			\
+"	orrmi	r0, r0, #0x80000000	@ set N\n" \
+"	teqp	r0, #0\n"			\
+"	movmi	r0, %0\n"			\
+	blmi	" SYMBOL_NAME_STR(fail)		\
+	:					\
+	: "r" (ptr)				\
+	: "r0", "lr", "cc");			\
+	})
 
-extern inline int down_trylock(struct semaphore * sem)
-{
-	int result;
-	__asm__ __volatile__ ("
-	@ atomic down operation
-	mov	r0, pc
-	orr	lr, r0, #0x08000000
-	teqp	lr, #0
-	ldr	lr, [%1]
-	and	r0, r0, #0x0c000003
-	subs	lr, lr, #1
-	str	lr, [%1]
-	orrmi	r0, r0, #0x80000000	@ set N
-	teqp	r0, #0
-	movmi	r0, %1
-	movpl	r0, #0
-	blmi	" SYMBOL_NAME_STR(__down_trylock_failed) "
-	mov	%0, r0"
-		: "=r" (result)
-		: "r" (sem)
-		: "r0", "lr", "cc");
-	return result;
-}
+#define __down_op_ret(ptr,fail)			\
+	({					\
+		unsigned int result;		\
+	__asm__ __volatile__ (			\
+"	@ down_op_ret\n"			\
+"	mov	r0, pc\n"			\
+"	orr	lr, r0, #0x08000000\n"		\
+"	teqp	lr, #0\n"			\
+"	ldr	lr, [%1]\m"			\
+"	and	r0, r0, #0x0c000003\n"		\
+"	subs	lr, lr, #1\n"			\
+"	str	lr, [%1]\n"			\
+"	orrmi	r0, r0, #0x80000000	@ set N\n" \
+"	teqp	r0, #0\n"			\
+"	movmi	r0, %1\n"			\
+"	movpl	r0, #0\n"			\
+"	blmi	" SYMBOL_NAME_STR(fail) "\n"	\
+"	mov	%0, r0"				\
+	: "=&r" (result)			\
+	: "r" (ptr)				\
+	: "r0", "lr", "cc");			\
+	result;					\
+	})
 
-/*
- * Note! This is subtle. We jump to wake people up only if
- * the semaphore was negative (== somebody was waiting on it).
- * The default case (no contention) will result in NO
- * jumps for both down() and up().
- */
-extern inline void up(struct semaphore * sem)
-{
-	__asm__ __volatile__ ("
-	@ atomic up operation
-	mov	r0, pc
-	orr	lr, r0, #0x08000000
-	teqp	lr, #0
-	ldr	lr, [%0]
-	and	r0, r0, #0x0c000003
-	adds	lr, lr, #1
-	str	lr, [%0]
-	orrle	r0, r0, #0x80000000	@ set N
-	teqp	r0, #0
-	movmi	r0, %0
-	blmi	" SYMBOL_NAME_STR(__up_wakeup)
-		:
-		: "r" (sem)
-		: "r0", "lr", "cc");
-}
+#define __up_op(ptr,wake)			\
+	({					\
+	__asm__ __volatile__ (			\
+	"@ up_op\n"				\
+	mov	r0, pc\n"			\
+	orr	lr, r0, #0x08000000\n"		\
+	teqp	lr, #0\n"			\
+	ldr	lr, [%0]\n"			\
+	and	r0, r0, #0x0c000003\n"		\
+	adds	lr, lr, #1\n"			\
+	str	lr, [%0]\n"			\
+	orrle	r0, r0, #0x80000000	@ set N\n" \
+	teqp	r0, #0\n"			\
+	movmi	r0, %0\n"			\
+	blmi	" SYMBOL_NAME_STR(wake)		\
+	:					\
+	: "r" (ptr)				\
+	: "r0", "lr", "cc");			\
+	})
 
 #endif
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/proc-armv/locks.h linux/include/asm-arm/proc-armv/locks.h
--- v2.3.44/linux/include/asm-arm/proc-armv/locks.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armv/locks.h	Sun Feb 13 10:47:01 2000
@@ -0,0 +1,134 @@
+/*
+ * linux/include/asm-arm/proc-armv/locks.h
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * Interrupt safe locking assembler. 
+ */
+#ifndef __ASM_PROC_LOCKS_H
+#define __ASM_PROC_LOCKS_H
+
+#define __down_op(ptr,fail)			\
+	({					\
+	__asm__ __volatile__(			\
+	"@ down_op\n"				\
+"	mrs	r0, cpsr\n"			\
+"	orr	lr, r0, #128\n"			\
+"	msr	cpsr_c, lr\n"			\
+"	ldr	lr, [%0]\n"			\
+"	subs	lr, lr, %1\n"			\
+"	str	lr, [%0]\n"			\
+"	msr	cpsr_c, r0\n"			\
+"	movmi	r0, %0\n"			\
+"	blmi	" SYMBOL_NAME_STR(fail)		\
+	:					\
+	: "r" (ptr), "I" (1)			\
+	: "r0", "lr", "cc");			\
+	})
+
+#define __down_op_ret(ptr,fail)			\
+	({					\
+		unsigned int ret;		\
+	__asm__ __volatile__(			\
+	"@ down_op_ret\n"			\
+"	mrs	r0, cpsr\n"			\
+"	orr	lr, r0, #128\n"			\
+"	msr	cpsr_c, lr\n"			\
+"	ldr	lr, [%1]\n"			\
+"	subs	lr, lr, %2\n"			\
+"	str	lr, [%1]\n"			\
+"	msr	cpsr_c, r0\n"			\
+"	movmi	r0, %1\n"			\
+"	movpl	r0, #0\n"			\
+"	blmi	" SYMBOL_NAME_STR(fail) "\n"	\
+"	mov	%0, r0"				\
+	: "=&r" (ret)				\
+	: "r" (ptr), "I" (1)			\
+	: "r0", "lr", "cc");			\
+	ret;					\
+	})
+
+#define __up_op(ptr,wake)			\
+	({					\
+	__asm__ __volatile__(			\
+	"@ up_op\n"				\
+"	mrs	r0, cpsr\n"			\
+"	orr	lr, r0, #128\n"			\
+"	msr	cpsr_c, lr\n"			\
+"	ldr	lr, [%0]\n"			\
+"	adds	lr, lr, %1\n"			\
+"	str	lr, [%0]\n"			\
+"	msr	cpsr_c, r0\n"			\
+"	movle	r0, %0\n"			\
+"	blle	" SYMBOL_NAME_STR(wake)		\
+	:					\
+	: "r" (ptr), "I" (1)			\
+	: "r0", "lr", "cc");			\
+	})
+
+/*
+ * The value 0x01000000 supports up to 128 processors and
+ * lots of processes.  BIAS must be chosen such that sub'ing
+ * BIAS once per CPU will result in the long remaining
+ * negative.
+ */
+#define RW_LOCK_BIAS	0x01000000
+
+#define __down_op_write(ptr,fail)		\
+	({					\
+	__asm__ __volatile__(			\
+	"@ down_op_write\n"			\
+"	mrs	r0, cpsr\n"			\
+"	orr	lr, r0, #128\n"			\
+"	msr	cpsr_c, lr\n"			\
+"	ldr	lr, [%0]\n"			\
+"	subs	lr, lr, %1\n"			\
+"	str	lr, [%0]\n"			\
+"	msr	cpsr_c, r0\n"			\
+"	movne	r0, %0\n"			\
+"	blne	" SYMBOL_NAME_STR(fail)		\
+	:					\
+	: "r" (ptr), "I" (RW_LOCK_BIAS)		\
+	: "r0", "lr", "cc");			\
+	})
+
+#define __up_op_write(ptr,wake)			\
+	({					\
+	__asm__ __volatile__(			\
+	"@ up_op_read\n"			\
+"	mrs	r0, cpsr\n"			\
+"	orr	lr, r0, #128\n"			\
+"	msr	cpsr_c, lr\n"			\
+"	ldr	lr, [%0]\n"			\
+"	adds	lr, lr, %1\n"			\
+"	str	lr, [%0]\n"			\
+"	msr	cpsr_c, r0\n"			\
+"	movcs	r0, %0\n"			\
+"	blcs	" SYMBOL_NAME_STR(wake)		\
+	:					\
+	: "r" (ptr), "I" (RW_LOCK_BIAS)		\
+	: "r0", "lr", "cc");			\
+	})
+
+#define __down_op_read(ptr,fail)		\
+	__down_op(ptr, fail)
+
+#define __up_op_read(ptr,wake)			\
+	({					\
+	__asm__ __volatile__(			\
+	"@ up_op_read\n"			\
+"	mrs	r0, cpsr\n"			\
+"	orr	lr, r0, #128\n"			\
+"	msr	cpsr_c, lr\n"			\
+"	ldr	lr, [%0]\n"			\
+"	adds	lr, lr, %1\n"			\
+"	str	lr, [%0]\n"			\
+"	msr	cpsr_c, r0\n"			\
+"	moveq	r0, %0\n"			\
+"	bleq	" SYMBOL_NAME_STR(wake)		\
+	:					\
+	: "r" (ptr), "I" (1)			\
+	: "r0", "lr", "cc");			\
+	})
+
+#endif
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/proc-armv/semaphore.h linux/include/asm-arm/proc-armv/semaphore.h
--- v2.3.44/linux/include/asm-arm/proc-armv/semaphore.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/proc-armv/semaphore.h	Wed Dec 31 16:00:00 1969
@@ -1,117 +0,0 @@
-/*
- * linux/include/asm-arm/semaphore.h
- */
-#ifndef __ASM_PROC_SEMAPHORE_H
-#define __ASM_PROC_SEMAPHORE_H
-
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down" is the actual routine that waits...
- */
-extern inline void down(struct semaphore * sem)
-{
-	unsigned int cpsr, temp;
-
-	__asm__ __volatile__ ("
-	@ atomic down operation
-	mrs	%0, cpsr
-	orr	%1, %0, #128		@ disable IRQs
-	msr	cpsr, %1
-	ldr	%1, [%2]
-	bic	%0, %0, #0x80000000	@ clear N
-	subs	%1, %1, #1
-	str	%1, [%2]
-	orrmi	%0, %0, #0x80000000	@ set N
-	msr	cpsr, %0
-	movmi	r0, %2
-	blmi	" SYMBOL_NAME_STR(__down_failed)
-		: "=&r" (cpsr), "=&r" (temp)
-		: "r" (sem)
-		: "r0", "lr", "cc");
-}
-
-/*
- * This is ugly, but we want the default case to fall through.
- * "__down_interruptible" is the actual routine that waits...
- */
-extern inline int down_interruptible (struct semaphore * sem)
-{
-	unsigned int cpsr, temp;
-
-	__asm__ __volatile__ ("
-	@ atomic down interruptible operation
-	mrs	%0, cpsr
-	orr	%1, %0, #128		@ disable IRQs
-	msr	cpsr, %1
-	ldr	%1, [%2]
-	bic	%0, %0, #0x80000000	@ clear N
-	subs	%1, %1, #1
-	str	%1, [%2]
-	orrmi	%0, %0, #0x80000000	@ set N
-	msr	cpsr, %0
-	movmi	r0, %2
-	movpl	r0, #0
-	blmi	" SYMBOL_NAME_STR(__down_interruptible_failed) "
-	mov	%1, r0"
-		: "=&r" (cpsr), "=&r" (temp)
-		: "r" (sem)
-		: "r0", "lr", "cc");
-
-	return temp;
-}
-
-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
-	msr	cpsr, %1
-	ldr	%1, [%2]
-	bic	%0, %0, #0x80000000	@ clear N
-	subs	%1, %1, #1
-	str	%1, [%2]
-	orrmi	%0, %0, #0x80000000	@ set N
-	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;
-}
-
-/*
- * Note! This is subtle. We jump to wake people up only if
- * the semaphore was negative (== somebody was waiting on it).
- * The default case (no contention) will result in NO
- * jumps for both down() and up().
- */
-extern inline void up(struct semaphore * sem)
-{
-	unsigned int cpsr, temp;
-
-	__asm__ __volatile__ ("
-	@ atomic up operation
-	mrs	%0, cpsr
-	orr	%1, %0, #128		@ disable IRQs
-	msr	cpsr, %1
-	ldr	%1, [%2]
-	bic	%0, %0, #0x80000000	@ clear N
-	adds	%1, %1, #1
-	str	%1, [%2]
-	orrle	%0, %0, #0x80000000	@ set N
-	msr	cpsr, %0
-	movmi	r0, %2
-	blmi	" SYMBOL_NAME_STR(__up_wakeup)
-		: "=&r" (cpsr), "=&r" (temp)
-		: "r" (sem)
-		: "r0", "lr", "cc");
-}
-
-#endif
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.3.44/linux/include/asm-arm/semaphore.h	Fri Oct 22 13:21:53 1999
+++ linux/include/asm-arm/semaphore.h	Sun Feb 13 10:47:01 2000
@@ -9,16 +9,28 @@
 #include <linux/wait.h>
 
 #include <asm/atomic.h>
+#include <asm/proc/locks.h>
 
 struct semaphore {
 	atomic_t count;
 	int sleepers;
 	wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+	long __magic;
+#endif
 };
 
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+		, (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
 #define __SEMAPHORE_INIT(name,count)			\
 	{ ATOMIC_INIT(count), 0,			\
-	  __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }
+	  __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)	\
+	  __SEM_DEBUG_INIT(name) }
 
 #define __MUTEX_INITIALIZER(name) \
 	__SEMAPHORE_INIT(name,1)
@@ -29,12 +41,15 @@
 #define DECLARE_MUTEX(name)		__DECLARE_SEMAPHORE_GENERIC(name,1)
 #define DECLARE_MUTEX_LOCKED(name)	__DECLARE_SEMAPHORE_GENERIC(name,0)
 
-#define sema_init(sem, val)			\
-do {						\
-	atomic_set(&((sem)->count), (val));	\
-	(sem)->sleepers = 0;			\
-	init_waitqueue_head(&(sem)->wait);	\
-} while (0)
+extern inline void sema_init(struct semaphore *sem, int val)
+{
+	atomic_set(&sem->count, val);
+	sem->sleepers = 0;
+	init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (long)&sem->__magic;
+#endif
+}
 
 static inline void init_MUTEX(struct semaphore *sem)
 {
@@ -46,18 +61,196 @@
 	sema_init(sem, 0);
 }
 
-asmlinkage void __down_failed (void /* special register calling convention */);
-asmlinkage int  __down_interruptible_failed (void /* special register calling convention */);
-asmlinkage int  __down_trylock_failed(void  /* params in registers */);
-asmlinkage void __up_wakeup (void /* special register calling convention */);
+/*
+ * special register calling convention
+ */
+asmlinkage void __down_failed(void);
+asmlinkage int  __down_interruptible_failed(void);
+asmlinkage int  __down_trylock_failed(void);
+asmlinkage void __up_wakeup(void);
 
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
 extern int  __down_trylock(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
-extern spinlock_t semaphore_wake_lock;
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "__down" is the actual routine that waits...
+ */
+extern inline void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	__down_op(sem, __down_failed);
+}
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "__down_interruptible" is the actual routine that waits...
+ */
+extern inline int down_interruptible (struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	return __down_op_ret(sem, __down_interruptible_failed);
+}
+
+extern inline int down_trylock(struct semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	return __down_op_ret(sem, __down_trylock_failed);
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+extern inline void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+
+	__up_op(sem, __up_wakeup);
+}
+
+/* rw mutexes (should that be mutices? =) -- throw rw
+ * spinlocks and semaphores together, and this is what we
+ * end up with...
+ *
+ * The lock is initialized to BIAS.  This way, a writer
+ * subtracts BIAS ands gets 0 for the case of an uncontended
+ * lock.  Readers decrement by 1 and see a positive value
+ * when uncontended, negative if there are writers waiting
+ * (in which case it goes to sleep).
+ *
+ * In terms of fairness, this should result in the lock
+ * flopping back and forth between readers and writers
+ * under heavy use.
+ *
+ *              -ben
+ */
+struct rw_semaphore {
+	atomic_t                count;
+	volatile unsigned char  write_bias_granted;
+	volatile unsigned char  read_bias_granted;
+	volatile unsigned char  pad1;
+	volatile unsigned char  pad2;
+	wait_queue_head_t       wait;
+	wait_queue_head_t	write_bias_wait;
+#if WAITQUEUE_DEBUG
+	long			__magic;
+	atomic_t		readers;
+	atomic_t		writers;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
+
+#define __RWSEM_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
+	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
+
+extern inline void init_rwsem(struct rw_semaphore *sem)
+{
+	atomic_set(&sem->count, RW_LOCK_BIAS);
+	sem->read_bias_granted = 0;
+	sem->write_bias_granted = 0;
+	init_waitqueue_head(&sem->wait);
+	init_waitqueue_head(&sem->write_bias_wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (long)&sem->__magic;
+	atomic_set(&sem->readers, 0);
+	atomic_set(&sem->writers, 0);
+#endif
+}
+
+extern struct rw_semaphore *__down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *__down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
+
+extern inline void down_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+	__down_op_read(sem, __down_read_failed);
+#if WAITQUEUE_DEBUG
+	if (sem->write_bias_granted)
+		BUG();
+	if (atomic_read(&sem->writers))
+		BUG();
+	atomic_inc(&sem->readers);
+#endif
+}
+
+extern inline void down_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+	__down_op_write(sem, __down_write_failed);
+#if WAITQUEUE_DEBUG
+	if (atomic_read(&sem->writers))
+		BUG();
+	if (atomic_read(&sem->readers))
+		BUG();
+	if (sem->read_bias_granted)
+		BUG();
+	if (sem->write_bias_granted)
+		BUG();
+	atomic_inc(&sem->writers);
+#endif
+}
 
-#include <asm/proc/semaphore.h>
+extern inline void up_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	if (sem->write_bias_granted)
+		BUG();
+	if (atomic_read(&sem->writers))
+		BUG();
+	atomic_dec(&sem->readers);
+#endif
+	__up_op_read(sem, __rwsem_wake);
+}
+
+extern inline void up_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+	if (sem->read_bias_granted)
+		BUG();
+	if (sem->write_bias_granted)
+		BUG();
+	if (atomic_read(&sem->readers))
+		BUG();
+	if (atomic_read(&sem->writers) != 1)
+		BUG();
+	atomic_dec(&sem->writers);
+#endif
+	__up_op_write(sem, __rwsem_wake);
+}
 
 #endif
diff -u --recursive --new-file v2.3.44/linux/include/asm-arm/softirq.h linux/include/asm-arm/softirq.h
--- v2.3.44/linux/include/asm-arm/softirq.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-arm/softirq.h	Sun Feb 13 10:47:01 2000
@@ -9,72 +9,9 @@
 #define cpu_bh_disable(cpu)	do { local_bh_count[(cpu)]++; barrier(); } while (0)
 #define cpu_bh_enable(cpu)	do { barrier(); local_bh_count[(cpu)]--; } while (0)
 
-#define cpu_bh_trylock(cpu)	(local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
-#define cpu_bh_endlock(cpu)	(local_bh_count[(cpu)] = 0)
-
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
 
-#define get_active_bhs()	(bh_mask & bh_active)
-#define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
-
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	atomic_set(&bh_mask_count[nr], 0);
-	bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	mb();
-	bh_base[nr] = NULL;
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-#ifdef __SMP__
-#error SMP not supported
-#else
-
-extern inline void start_bh_atomic(void)
-{
-	local_bh_disable();
-	barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
-	barrier();
-	local_bh_enable();
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)	(cpu_bh_trylock(cpu))
-#define softirq_endlock(cpu)	(cpu_bh_endlock(cpu))
-#define synchronize_bh()	barrier()
-
-#endif	/* SMP */
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	atomic_inc(&bh_mask_count[nr]);
-	synchronize_bh();
-}
-
-extern inline void enable_bh(int nr)
-{
-	if (atomic_dec_and_test(&bh_mask_count[nr]))
-		bh_mask |= 1 << nr;
-}
+#define in_softirq()		(local_bh_count[smp_processor_id()] != 0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.3.44/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.3.44/linux/include/asm-i386/pgtable.h	Sat Feb 12 11:22:11 2000
+++ linux/include/asm-i386/pgtable.h	Sun Feb 13 19:04:10 2000
@@ -26,6 +26,7 @@
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_page(vma,pg)		do { } while (0)
 
 #define __flush_tlb()							\
 	do {								\
@@ -292,10 +293,11 @@
 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 
 /* to find an entry in a page-table-directory. */
-#define __pgd_offset(address) \
-		((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 
-#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address))
+#define __pgd_offset(address) pgd_index(address)
+
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/dma.h linux/include/asm-ia64/dma.h
--- v2.3.44/linux/include/asm-ia64/dma.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/dma.h	Sun Feb 13 10:30:44 2000
@@ -6,11 +6,11 @@
  * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-#include <asm/io.h>		/* need byte IO */
 #include <linux/config.h>
 #include <linux/spinlock.h>	/* And spinlocks */
 #include <linux/delay.h>
 
+#include <asm/io.h>		/* need byte IO */
 
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
 #define dma_outb	outb_p
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/fpswa.h linux/include/asm-ia64/fpswa.h
--- v2.3.44/linux/include/asm-ia64/fpswa.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/fpswa.h	Sun Feb 13 10:30:50 2000
@@ -9,7 +9,7 @@
  * Copyright (C) 1999 Goutham Rao <goutham.rao@intel.com>
  */
 
-#if 0
+#if 1
 #define FPSWA_BUG
 #endif
 
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/hardirq.h linux/include/asm-ia64/hardirq.h
--- v2.3.44/linux/include/asm-ia64/hardirq.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/hardirq.h	Sun Feb 13 10:31:06 2000
@@ -17,11 +17,15 @@
  * or hardware interrupt processing?
  */
 
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+
 #define in_interrupt()						\
 ({								\
 	int __cpu = smp_processor_id();				\
 	(local_irq_count[__cpu] + local_bh_count[__cpu]) != 0;	\
 })
+
+
 
 #ifndef CONFIG_SMP
 # define hardirq_trylock(cpu)		(local_irq_count[cpu] == 0)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/mmu_context.h linux/include/asm-ia64/mmu_context.h
--- v2.3.44/linux/include/asm-ia64/mmu_context.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/mmu_context.h	Sun Feb 13 10:31:06 2000
@@ -60,6 +60,11 @@
 
 extern void get_new_mmu_context (struct mm_struct *mm);
 
+static inline void
+enter_lazy_tlb (struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+
 extern inline unsigned long
 ia64_rid (unsigned long context, unsigned long region_addr)
 {
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h
--- v2.3.44/linux/include/asm-ia64/offsets.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/offsets.h	Sun Feb 13 10:31:06 2000
@@ -10,7 +10,7 @@
 
 #define PF_PTRACED_BIT			4
 
-#define IA64_TASK_SIZE			2752	/* 0xac0 */
+#define IA64_TASK_SIZE			3280	/* 0xcd0 */
 #define IA64_PT_REGS_SIZE		400	/* 0x190 */
 #define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
 #define IA64_SIGINFO_SIZE		136	/* 0x88 */
@@ -18,8 +18,9 @@
 #define IA64_TASK_FLAGS_OFFSET		8	/* 0x8 */
 #define IA64_TASK_SIGPENDING_OFFSET	16	/* 0x10 */
 #define IA64_TASK_NEED_RESCHED_OFFSET	40	/* 0x28 */
-#define IA64_TASK_THREAD_OFFSET		912	/* 0x390 */
-#define IA64_TASK_THREAD_KSP_OFFSET	912	/* 0x390 */
+#define IA64_TASK_PROCESSOR_OFFSET	108	/* 0x6c */
+#define IA64_TASK_THREAD_OFFSET		1424	/* 0x590 */
+#define IA64_TASK_THREAD_KSP_OFFSET	1424	/* 0x590 */
 #define IA64_TASK_PID_OFFSET		188	/* 0xbc */
 #define IA64_TASK_MM_OFFSET		88	/* 0x58 */
 #define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h
--- v2.3.44/linux/include/asm-ia64/pgtable.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/pgtable.h	Sun Feb 13 10:31:06 2000
@@ -187,9 +187,14 @@
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
+
 extern void ia64_flush_icache_page (unsigned long addr);
 
-#define flush_icache_page(pg)	ia64_flush_icache_page(page_address(pg))
+#define flush_icache_page(vma,pg)				\
+do {								\
+	if ((vma)->vm_flags & PROT_EXEC)			\
+		ia64_flush_icache_page(page_address(pg));	\
+} while (0)
 
 /*
  * Now come the defines and routines to manage and access the three-level
@@ -289,15 +294,21 @@
  */
 #define pgprot_noncached(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC)
 
+extern __inline__ unsigned long
+pgd_index (unsigned long address)
+{
+	unsigned long region = address >> 61;
+	unsigned long l1index = (address >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
+
+	return (region << (PAGE_SHIFT - 6)) | l1index;
+}
+
 /* The offset in the 1-level directory is given by the 3 region bits
    (61..63) and the seven level-1 bits (33-39).  */
 extern __inline__ pgd_t*
 pgd_offset (struct mm_struct *mm, unsigned long address)
 {
-	unsigned long region = address >> 61;
-	unsigned long l1index = (address >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
-
-	return mm->pgd + ((region << (PAGE_SHIFT - 6)) | l1index);
+	return mm->pgd + pgd_index(address);
 }
 
 /* In the kernel's mapped region we have a full 43 bit space available and completely
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/ptrace.h linux/include/asm-ia64/ptrace.h
--- v2.3.44/linux/include/asm-ia64/ptrace.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/ptrace.h	Sun Feb 13 10:31:06 2000
@@ -145,10 +145,10 @@
 	 * Floating point registers that the kernel considers
 	 * scratch:
 	 */
-	struct ia64_fpreg f6;		/* scratch*/
-	struct ia64_fpreg f7;		/* scratch*/
-	struct ia64_fpreg f8;		/* scratch*/
-	struct ia64_fpreg f9;		/* scratch*/
+	struct ia64_fpreg f6;		/* scratch */
+	struct ia64_fpreg f7;		/* scratch */
+	struct ia64_fpreg f8;		/* scratch */
+	struct ia64_fpreg f9;		/* scratch */
 };
 
 /*
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/semaphore.h linux/include/asm-ia64/semaphore.h
--- v2.3.44/linux/include/asm-ia64/semaphore.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/semaphore.h	Sun Feb 13 10:31:06 2000
@@ -137,13 +137,6 @@
  * In terms of fairness, when there is heavy use of the lock, we want
  * to see the lock being passed back and forth between readers and
  * writers (like in a producer/consumer style of communication).
- * 
-
-  For
- * liveness, it would be necessary to process the blocked readers and
- * writers in FIFO order.  However, we don't do this (yet).  I suppose
- * if you have a lock that is _that_ heavily contested, you're in big
- * trouble anyhow.
  *
  *	      -ben (with clarifications & IA-64 comments by davidm)
  */
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h
--- v2.3.44/linux/include/asm-ia64/smp.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/smp.h	Sun Feb 13 10:31:06 2000
@@ -8,6 +8,7 @@
 #define _ASM_IA64_SMP_H
 
 #include <linux/config.h>
+
 #include <linux/init.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
@@ -25,9 +26,10 @@
 extern unsigned long cpu_online_map;
 extern unsigned long ipi_base_addr;
 extern int bootstrap_processor;
-extern volatile int cpu_number_map[NR_CPUS];
+extern volatile int __cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
 
+#define cpu_number_map(i)	__cpu_number_map[i]
 #define cpu_logical_map(i)	__cpu_logical_map[i]
 
 #if defined(CONFIG_KDB)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/softirq.h linux/include/asm-ia64/softirq.h
--- v2.3.44/linux/include/asm-ia64/softirq.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/softirq.h	Sun Feb 13 10:31:07 2000
@@ -2,13 +2,9 @@
 #define _ASM_IA64_SOFTIRQ_H
 
 /*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
-#include <linux/config.h>
-#include <linux/stddef.h>
-
-#include <asm/system.h>
 #include <asm/hardirq.h>
 
 extern unsigned int local_bh_count[NR_CPUS];
@@ -16,137 +12,9 @@
 #define cpu_bh_disable(cpu)	do { local_bh_count[(cpu)]++; barrier(); } while (0)
 #define cpu_bh_enable(cpu)	do { barrier(); local_bh_count[(cpu)]--; } while (0)
 
-#define cpu_bh_trylock(cpu)	(local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
-#define cpu_bh_endlock(cpu)	(local_bh_count[(cpu)] = 0)
-
 #define local_bh_disable()	cpu_bh_disable(smp_processor_id())
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
 
-#define get_active_bhs()	(bh_mask & bh_active)
-
-static inline void
-clear_active_bhs (unsigned long x)
-{
-	unsigned long old, new;
-	volatile unsigned long *bh_activep = (void *) &bh_active;
-	CMPXCHG_BUGCHECK_DECL
-
-	do {
-		CMPXCHG_BUGCHECK(bh_activep);
-		old = *bh_activep;
-		new = old & ~x;
-	} while (ia64_cmpxchg(bh_activep, old, new, 8) != old);
-}
-
-extern inline void
-init_bh (int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	atomic_set(&bh_mask_count[nr], 0);
-	bh_mask |= 1 << nr;
-}
-
-extern inline void
-remove_bh (int nr)
-{
-	bh_mask &= ~(1 << nr);
-	mb();
-	bh_base[nr] = NULL;
-}
-
-extern inline void
-mark_bh (int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-#ifdef CONFIG_SMP
-
-/*
- * The locking mechanism for base handlers, to prevent re-entrancy,
- * is entirely private to an implementation, it should not be
- * referenced at all outside of this file.
- */
-extern atomic_t global_bh_lock;
-extern atomic_t global_bh_count;
-
-extern void synchronize_bh(void);
-
-static inline void
-start_bh_atomic (void)
-{
-	atomic_inc(&global_bh_lock);
-	synchronize_bh();
-}
-
-static inline void
-end_bh_atomic (void)
-{
-	atomic_dec(&global_bh_lock);
-}
-
-/* These are for the irq's testing the lock */
-static inline int
-softirq_trylock (int cpu)
-{
-	if (cpu_bh_trylock(cpu)) {
-		if (!test_and_set_bit(0, &global_bh_count)) {
-			if (atomic_read(&global_bh_lock) == 0)
-				return 1;
-			clear_bit(0,&global_bh_count);
-		}
-		cpu_bh_endlock(cpu);
-	}
-	return 0;
-}
-
-static inline void
-softirq_endlock (int cpu)
-{
-	cpu_bh_enable(cpu);
-	clear_bit(0,&global_bh_count);
-}
-
-#else /* !CONFIG_SMP */
-
-extern inline void
-start_bh_atomic (void)
-{
-	local_bh_disable();
-	barrier();
-}
-
-extern inline void
-end_bh_atomic (void)
-{
-	barrier();
-	local_bh_enable();
-}
-
-/* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)	(cpu_bh_trylock(cpu))
-#define softirq_endlock(cpu)	(cpu_bh_endlock(cpu))
-#define synchronize_bh()	barrier()
-
-#endif /* !CONFIG_SMP */
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void
-disable_bh (int nr)
-{
-	bh_mask &= ~(1 << nr);
-	atomic_inc(&bh_mask_count[nr]);
-	synchronize_bh();
-}
-
-extern inline void
-enable_bh (int nr)
-{
-	if (atomic_dec_and_test(&bh_mask_count[nr]))
-		bh_mask |= 1 << nr;
-}
+#define in_softirq()		(local_bh_count[smp_processor_id()] != 0)
 
 #endif /* _ASM_IA64_SOFTIRQ_H */
diff -u --recursive --new-file v2.3.44/linux/include/asm-ia64/types.h linux/include/asm-ia64/types.h
--- v2.3.44/linux/include/asm-ia64/types.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-ia64/types.h	Sun Feb 13 10:31:07 2000
@@ -8,8 +8,8 @@
  * not a major issue.  However, for interoperability, libraries still
  * need to be careful to avoid a name clashes.
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #ifdef __ASSEMBLY__
@@ -38,51 +38,27 @@
 typedef __signed__ int __s32;
 typedef unsigned int __u32;
 
-/*
- * There are 32-bit compilers for the ia-64 out there..
- */
-# if ((~0UL) == 0xffffffff)
-#  if defined(__GNUC__) && !defined(__STRICT_ANSI__)
-typedef __signed__ long long __s64;
-typedef unsigned long long __u64;
-#  endif
-# else
 typedef __signed__ long __s64;
 typedef unsigned long __u64;
-# endif
 
 /*
  * These aren't exported outside the kernel to avoid name space clashes
  */
 # ifdef __KERNEL__
 
-typedef signed char s8;
-typedef unsigned char u8;
+typedef __s8 s8;
+typedef __u8 u8;
 
-typedef signed short s16;
-typedef unsigned short u16;
+typedef __s16 s16;
+typedef __u16 u16;
 
-typedef signed int s32;
-typedef unsigned int u32;
+typedef __s32 s32;
+typedef __u32 u32;
 
-/*
- * There are 32-bit compilers for the ia-64 out there...  (don't rely
- * on cpp because that may cause su problem in a 32->64 bit
- * cross-compilation environment).
- */
-#  ifdef __LP64__
+typedef __s64 s64;
+typedef __u64 u64;
 
-typedef signed long s64;
-typedef unsigned long u64;
 #define BITS_PER_LONG 64
-
-#  else
-
-typedef signed long long s64;
-typedef unsigned long long u64;
-#define BITS_PER_LONG 32
-
-#  endif
 
 /* DMA addresses are 64-bits wide, in general.  */
 
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/adb_iop.h linux/include/asm-m68k/adb_iop.h
--- v2.3.44/linux/include/asm-m68k/adb_iop.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/adb_iop.h	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,44 @@
+/*
+ * ADB through the IOP
+ * Written by Joshua M. Thompson
+ */
+
+/* IOP number and channel number for ADB */
+
+#define ADB_IOP		IOP_NUM_ISM
+#define ADB_CHAN	2
+
+/* From the A/UX headers...maybe important, maybe not */
+
+#define ADB_IOP_LISTEN	0x01
+#define ADB_IOP_TALK	0x02
+#define ADB_IOP_EXISTS	0x04
+#define ADB_IOP_FLUSH	0x08
+#define ADB_IOP_RESET	0x10
+#define ADB_IOP_INT	0x20
+#define ADB_IOP_POLL	0x40
+#define ADB_IOP_UNINT	0x80
+
+#define AIF_RESET	0x00
+#define AIF_FLUSH	0x01
+#define AIF_LISTEN	0x08
+#define AIF_TALK	0x0C
+
+/* Flag bits in struct adb_iopmsg */
+
+#define ADB_IOP_EXPLICIT	0x80	/* nonzero if explicit command */
+#define ADB_IOP_AUTOPOLL	0x40	/* auto/SRQ polling enabled    */
+#define ADB_IOP_SRQ		0x04	/* SRQ detected                */
+#define ADB_IOP_TIMEOUT		0x02	/* nonzero if timeout          */
+
+#ifndef __ASSEMBLY__
+
+struct adb_iopmsg {
+	__u8 flags;		/* ADB flags         */
+	__u8 count;		/* no. of data bytes */
+	__u8 cmd;		/* ADB command       */
+	__u8 data[8];		/* ADB data          */
+	__u8 spare[21];		/* spare             */
+};
+
+#endif /* __ASSEMBLY__ */
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h
--- v2.3.44/linux/include/asm-m68k/hardirq.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-m68k/hardirq.h	Sun Feb 13 11:21:42 2000
@@ -7,6 +7,8 @@
 
 #define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
 
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
 
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/irq.h linux/include/asm-m68k/irq.h
--- v2.3.44/linux/include/asm-m68k/irq.h	Sun Aug 15 11:47:29 1999
+++ linux/include/asm-m68k/irq.h	Sun Feb 13 11:21:42 2000
@@ -15,7 +15,7 @@
  * Currently the Atari has 72 and the Amiga 24, but if both are
  * supported in the kernel it is better to make room for 72.
  */
-#if defined(CONFIG_ATARI)
+#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
 #define NR_IRQS (72+SYS_IRQS)
 #else
 #define NR_IRQS (24+SYS_IRQS)
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/mac_baboon.h linux/include/asm-m68k/mac_baboon.h
--- v2.3.44/linux/include/asm-m68k/mac_baboon.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mac_baboon.h	Sun Feb 13 11:21:42 2000
@@ -0,0 +1,34 @@
+/*
+ * Definitions for the "Baboon" custom IC on the PowerBook 190.
+ */
+
+#define BABOON_BASE (0x50F1A000)	/* same as IDE controller base */
+
+#ifndef __ASSEMBLY__
+
+struct baboon {
+	char	pad1[208];	/* generic IDE registers, not used here */
+	short	mb_control;	/* Control register:
+				 * bit 5 : slot 2 power control
+				 * bit 6 : slot 1 power control
+				 */
+	char	pad2[2];
+	short	mb_status;	/* (0xD4) media bay status register:
+				 *
+				 * bit 0: ????
+				 * bit 1: IDE interrupt active?
+				 * bit 2: bay status, 0 = full, 1 = empty
+				 * bit 3: ????
+				 */
+	char	pad3[2];	/* (0xD6) not used */
+	short	mb_ifr;		/* (0xD8) media bay interrupt flags register:
+				 *
+				 * bit 0: ????
+				 * bit 1: IDE controller interrupt
+				 * bit 2: media bay status change interrupt
+				 */
+};
+
+extern volatile struct baboon *baboon;
+
+#endif /* __ASSEMBLY **/
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/macintosh.h linux/include/asm-m68k/macintosh.h
--- v2.3.44/linux/include/asm-m68k/macintosh.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/macintosh.h	Sun Feb 13 11:21:42 2000
@@ -74,6 +74,7 @@
 #define MAC_IDE_NONE		0
 #define MAC_IDE_QUADRA		1
 #define MAC_IDE_PB		2
+#define MAC_IDE_BABOON		3
 
 #define MAC_SCC_II		1
 #define MAC_SCC_QUADRA		2
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/macints.h linux/include/asm-m68k/macints.h
--- v2.3.44/linux/include/asm-m68k/macints.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/macints.h	Sun Feb 13 11:21:42 2000
@@ -43,13 +43,14 @@
 #define PSC5_SOURCE_BASE	40
 #define PSC6_SOURCE_BASE	48
 #define NUBUS_SOURCE_BASE	56
+#define BABOON_SOURCE_BASE	64
 
 /*
- * Maximum IRQ number is NUBUS_SOURCE_BASE + 7,
- * giving us IRQs up through 63.
+ * Maximum IRQ number is BABOON_SOURCE_BASE + 7,
+ * giving us IRQs up through 71
  */
 
-#define NUM_MAC_SOURCES		64
+#define NUM_MAC_SOURCES		72
 
 /* 
  * clean way to separate IRQ into its source and index
@@ -149,6 +150,12 @@
 #define IRQ_NUBUS_D	  (60)
 #define IRQ_NUBUS_E	  (61)
 #define IRQ_NUBUS_F	  (62)
+
+/* Baboon interrupts (cascaded to nubus slot $C) */
+#define IRQ_BABOON_0	  (64)
+#define IRQ_BABOON_1	  (65)
+#define IRQ_BABOON_2	  (66)
+#define IRQ_BABOON_3	  (67)
 
 #define SLOT2IRQ(x)	  (x + 47)
 #define IRQ2SLOT(x)	  (x - 47)
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.3.44/linux/include/asm-m68k/pgtable.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-m68k/pgtable.h	Sun Feb 13 10:31:07 2000
@@ -285,10 +285,12 @@
 
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
+#define pgd_index(address)	((address) >> PGDIR_SHIFT)
+
 /* 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);
+	return mm->pgd + pgd_index(address);
 }
 
 #define swapper_pg_dir kernel_pg_dir
diff -u --recursive --new-file v2.3.44/linux/include/asm-m68k/softirq.h linux/include/asm-m68k/softirq.h
--- v2.3.44/linux/include/asm-m68k/softirq.h	Mon Aug  9 12:27:31 1999
+++ linux/include/asm-m68k/softirq.h	Sun Feb 13 11:21:42 2000
@@ -7,59 +7,12 @@
 
 #include <asm/atomic.h>
 
-#define get_active_bhs()	(bh_mask & bh_active)
-#define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
-
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	atomic_set(&bh_mask_count[nr], 0);
-	bh_mask |= 1 << nr;
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	atomic_inc(&bh_mask_count[nr]);
-}
-
-extern inline void enable_bh(int nr)
-{
-	if (atomic_dec_and_test(&bh_mask_count[nr]))
-		bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
-	bh_base[nr] = NULL;
-	bh_mask &= ~(1 << nr);
-}
-
 extern unsigned int local_bh_count[NR_CPUS];
 
 #define local_bh_disable()	(local_bh_count[smp_processor_id()]++)
 #define local_bh_enable()	(local_bh_count[smp_processor_id()]--)
 
-extern inline void start_bh_atomic(void)
-{
-	local_bh_count[smp_processor_id()]++;
-	barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
-	barrier();
-	local_bh_count[smp_processor_id()]--;
-}
+#define in_softirq() (local_bh_count != 0)
 
 /* These are for the irq's testing the lock */
 #define softirq_trylock(cpu)  (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
diff -u --recursive --new-file v2.3.44/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.3.44/linux/include/asm-mips/pgtable.h	Thu Feb 10 17:11:20 2000
+++ linux/include/asm-mips/pgtable.h	Sun Feb 13 10:31:07 2000
@@ -371,10 +371,12 @@
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
+#define pgd_index(address)	((address) >> PGDIR_SHIFT)
+
 /* 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);
+	return mm->pgd + pgd_index(address);
 }
 
 /* Find an entry in the second-level page table.. */
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- v2.3.44/linux/include/asm-ppc/elf.h	Wed Sep 30 10:14:33 1998
+++ linux/include/asm-ppc/elf.h	Sun Feb 13 10:47:01 2000
@@ -8,6 +8,7 @@
 
 #define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
 #define ELF_NFPREG	33	/* includes fpscr */
+#define ELF_NVRREG	33	/* includes vscr */
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -36,6 +37,10 @@
 
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/* Altivec registers */
+typedef vector128 elf_vrreg_t;
+typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
 
 #define ELF_CORE_COPY_REGS(gregs, regs) \
 	memcpy(gregs, regs, \
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.3.44/linux/include/asm-ppc/hardirq.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-ppc/hardirq.h	Sun Feb 13 10:47:01 2000
@@ -3,22 +3,24 @@
 
 #include <asm/smp.h>
 
-extern unsigned int ppc_local_irq_count[NR_CPUS];
+extern unsigned int local_irq_count[NR_CPUS];
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
  */
 #define in_interrupt() ({ int __cpu = smp_processor_id(); \
-	(ppc_local_irq_count[__cpu] + ppc_local_bh_count[__cpu] != 0); })
+	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+
+#define in_irq() (local_irq_count[smp_processor_id()] != 0)
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	(ppc_local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
 
-#define hardirq_enter(cpu)	(ppc_local_irq_count[cpu]++)
-#define hardirq_exit(cpu)	(ppc_local_irq_count[cpu]--)
+#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
+#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
 
 #define synchronize_irq()	do { } while (0)
 
@@ -41,14 +43,31 @@
 
 static inline void hardirq_enter(int cpu)
 {
-	++ppc_local_irq_count[cpu];
+	unsigned int loops = 10000000;
+	
+	++local_irq_count[cpu];
 	atomic_inc(&global_irq_count);
+	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
+		}
+	}
 }
 
 static inline void hardirq_exit(int cpu)
 {
 	atomic_dec(&global_irq_count);
-	--ppc_local_irq_count[cpu];
+	--local_irq_count[cpu];
 }
 
 static inline int hardirq_trylock(int cpu)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.3.44/linux/include/asm-ppc/page.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-ppc/page.h	Sun Feb 13 10:47:01 2000
@@ -77,7 +77,7 @@
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 extern void clear_page(void *page);
-#define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+extern void copy_page(void *to, void *from);
 
 /* map phys->virtual and virtual->phys for RAM pages */
 static inline unsigned long ___pa(unsigned long v)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.44/linux/include/asm-ppc/pgtable.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-ppc/pgtable.h	Sun Feb 13 10:31:07 2000
@@ -413,7 +413,8 @@
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* to find an entry in a page-table-directory */
-#define pgd_offset(mm, address)	 ((mm)->pgd + ((address) >> PGDIR_SHIFT))
+#define pgd_index(address)	 ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
 
 /* Find an entry in the second-level page table.. */
 extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/posix_types.h linux/include/asm-ppc/posix_types.h
--- v2.3.44/linux/include/asm-ppc/posix_types.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-ppc/posix_types.h	Sun Feb 13 10:47:01 2000
@@ -24,8 +24,8 @@
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef short             __kernel_ipc_pid_t;
-typedef unsigned int	__kernel_uid16_t;
-typedef unsigned int	__kernel_gid16_t;
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
 typedef unsigned int	__kernel_uid32_t;
 typedef unsigned int	__kernel_gid32_t;
 
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.3.44/linux/include/asm-ppc/processor.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-ppc/processor.h	Sun Feb 13 10:47:01 2000
@@ -11,6 +11,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/residual.h>
+#include <asm/types.h>
 
 /* Machine State Register (MSR) Fields */
 
@@ -625,9 +626,11 @@
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
 	unsigned long	fpscr;		/* Floating point status */
-	unsigned long	vrf[128];
-	unsigned long	vscr;
+#ifdef CONFIG_ALTIVEC
+	vector128	vr[32];		/* Complete AltiVec set */
+	vector128	vscr;		/* AltiVec status */
 	unsigned long	vrsave;
+#endif /* CONFIG_ALTIVEC */
 };
 
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.3.44/linux/include/asm-ppc/smp.h	Mon Dec 20 18:48:22 1999
+++ linux/include/asm-ppc/smp.h	Sun Feb 13 10:47:01 2000
@@ -33,7 +33,7 @@
 
 /* 1 to 1 mapping on PPC -- Cort */
 #define cpu_logical_map(cpu) (cpu)
-extern int cpu_number_map[NR_CPUS];
+#define cpu_number_map(x) (x)
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
 
 #define hard_smp_processor_id() (0)
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.3.44/linux/include/asm-ppc/softirq.h	Fri Sep 10 23:57:37 1999
+++ linux/include/asm-ppc/softirq.h	Sun Feb 13 10:47:01 2000
@@ -4,116 +4,11 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define get_active_bhs()	(bh_mask & bh_active)
-#define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
+extern unsigned int local_bh_count[NR_CPUS];
 
-extern unsigned int ppc_local_bh_count[NR_CPUS];
+#define local_bh_disable()	do { local_bh_count[smp_processor_id()]++; barrier(); } while (0)
+#define local_bh_enable()	do { barrier(); local_bh_count[smp_processor_id()]--; } while (0)
 
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	atomic_set(&bh_mask_count[nr], 0);
-	bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	wmb();
-	bh_base[nr] = 0;
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-#ifdef __SMP__
-
-/*
- * The locking mechanism for base handlers, to prevent re-entrancy,
- * is entirely private to an implementation, it should not be
- * referenced at all outside of this file.
- */
-extern atomic_t global_bh_lock;
-extern atomic_t global_bh_count;
-
-extern void synchronize_bh(void);
-
-static inline void start_bh_atomic(void)
-{
-	atomic_inc(&global_bh_lock);
-	synchronize_bh();
-}
-
-static inline void end_bh_atomic(void)
-{
-	atomic_dec(&global_bh_lock);
-}
-
-/* These are for the IRQs testing the lock */
-static inline int softirq_trylock(int cpu)
-{
-	if (ppc_local_bh_count[cpu] == 0) {
-		ppc_local_bh_count[cpu] = 1;
-		if (!test_and_set_bit(0,&global_bh_count)) {
-			mb();
-			if (atomic_read(&global_bh_lock) == 0)
-				return 1;
-			clear_bit(0,&global_bh_count);
-		}
-		ppc_local_bh_count[cpu] = 0;
-		mb();
-	}
-	return 0;
-}
-
-static inline void softirq_endlock(int cpu)
-{
-	mb();
-	ppc_local_bh_count[cpu]--;
-	clear_bit(0,&global_bh_count);
-}
-
-#else
-
-extern inline void start_bh_atomic(void)
-{
-	ppc_local_bh_count[smp_processor_id()]++;
-	barrier();
-}
-
-extern inline void end_bh_atomic(void)
-{
-	barrier();
-	ppc_local_bh_count[smp_processor_id()]--;
-}
-
-/* These are for the irq's testing the lock */
-#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()
-
-#endif	/* SMP */
-
-#define local_bh_disable()	(ppc_local_bh_count[smp_processor_id()]++)
-#define local_bh_enable()	(ppc_local_bh_count[smp_processor_id()]--)
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	atomic_inc(&bh_mask_count[nr]);
-	synchronize_bh();
-}
-
-extern inline void enable_bh(int nr)
-{
-	if (atomic_dec_and_test(&bh_mask_count[nr]))
-		bh_mask |= 1 << nr;
-}
+#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h
--- v2.3.44/linux/include/asm-ppc/spinlock.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/spinlock.h	Sun Feb 13 10:47:01 2000
@@ -14,6 +14,7 @@
 #define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0, 0, 0 }
 #define spin_lock_init(lp) 	do { (lp)->lock = 0; } while(0)
 #define spin_unlock_wait(lp)	do { barrier(); } while((lp)->lock)
+#define spin_is_locked(x)	((x)->lock != 0)
 
 extern void _spin_lock(spinlock_t *lock);
 extern void _spin_unlock(spinlock_t *lock);
diff -u --recursive --new-file v2.3.44/linux/include/asm-ppc/types.h linux/include/asm-ppc/types.h
--- v2.3.44/linux/include/asm-ppc/types.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-ppc/types.h	Sun Feb 13 10:47:01 2000
@@ -1,6 +1,7 @@
 #ifndef _PPC_TYPES_H
 #define _PPC_TYPES_H
 
+#ifndef __ASSEMBLY__
 /*
  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
  * header files exported to user space
@@ -41,10 +42,15 @@
 
 #define BITS_PER_LONG 32
 
+typedef struct {
+	u32 u[4];
+} __attribute((aligned(16))) vector128;
+
 /* DMA addresses are 32-bits wide */
 
 typedef u32 dma_addr_t;
 
 #endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
 
 #endif
diff -u --recursive --new-file v2.3.44/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- v2.3.44/linux/include/asm-sh/pgtable.h	Thu Feb 10 17:11:21 2000
+++ linux/include/asm-sh/pgtable.h	Sun Feb 13 10:31:07 2000
@@ -250,10 +250,9 @@
 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 
 /* to find an entry in a page-table-directory. */
-#define __pgd_offset(address) \
-		((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-
-#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address))
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define __pgd_offset(address) pgd_index(address)
+#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
diff -u --recursive --new-file v2.3.44/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.3.44/linux/include/asm-sparc64/floppy.h	Tue Feb  1 01:35:44 2000
+++ linux/include/asm-sparc64/floppy.h	Sun Feb 13 10:18:03 2000
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.25 2000/01/28 13:43:14 jj Exp $
+/* $Id: floppy.h,v 1.26 2000/02/12 23:32:35 davem Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -727,8 +727,8 @@
 	 * which the generic floppy driver tries to do once again.
 	 */
 	sun_fdc = (struct sun_flpy_controller *)
-		(PAGE_OFFSET + fd_regs[0].phys_addr + 
-		 (((unsigned long)fd_regs[0].which_io) << 32));
+		((unsigned long)fd_regs[0].phys_addr + 
+		 (((unsigned long)fd_regs[0].which_io) << 32UL));
 
 	/* Last minute sanity check... */
 	if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
diff -u --recursive --new-file v2.3.44/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.44/linux/include/asm-sparc64/pgtable.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc64/pgtable.h	Sun Feb 13 10:31:07 2000
@@ -235,7 +235,8 @@
 }
 
 /* to find an entry in a page-table-directory. */
-#define pgd_offset(mm, address) ((mm)->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD)))
+#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD))
+#define pgd_offset(mm, address)	((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
diff -u --recursive --new-file v2.3.44/linux/include/linux/adfs_fs_i.h linux/include/linux/adfs_fs_i.h
--- v2.3.44/linux/include/linux/adfs_fs_i.h	Thu Feb 10 17:11:21 2000
+++ linux/include/linux/adfs_fs_i.h	Sun Feb 13 10:45:13 2000
@@ -11,7 +11,7 @@
  * adfs file system inode data in memory
  */
 struct adfs_inode_info {
-	unsigned long mmu_private;
+	unsigned long	mmu_private;
 	unsigned long	parent_id;	/* object id of parent		*/
 	__u32		loadaddr;	/* RISC OS load address		*/
 	__u32		execaddr;	/* RISC OS exec address		*/
diff -u --recursive --new-file v2.3.44/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.44/linux/include/linux/fs.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/fs.h	Sun Feb 13 19:04:14 2000
@@ -349,7 +349,8 @@
 	unsigned long		nrpages;	/* number of pages */
 	struct address_space_operations *a_ops;	/* methods */
 	void			*host;		/* owner: inode, block_device */
-	void			*private;	/* private data */
+	struct vm_area_struct	*i_mmap;	/* list of mappings */
+	spinlock_t		i_shared_lock;  /* and spinlock protecting it */
 };
 
 struct block_device {
@@ -387,10 +388,8 @@
 	struct super_block	*i_sb;
 	wait_queue_head_t	i_wait;
 	struct file_lock	*i_flock;
-	struct vm_area_struct	*i_mmap;
-	struct address_space	*i_mapping;	
+	struct address_space	*i_mapping;
 	struct address_space	i_data;	
-	spinlock_t		i_shared_lock;
 	struct dquot		*i_dquot[MAXQUOTAS];
 	struct pipe_inode_info	*i_pipe;
 	struct block_device	*i_bdev;
diff -u --recursive --new-file v2.3.44/linux/include/linux/i2c-id.h linux/include/linux/i2c-id.h
--- v2.3.44/linux/include/linux/i2c-id.h	Thu Feb 10 17:11:22 2000
+++ linux/include/linux/i2c-id.h	Sun Feb 13 10:45:13 2000
@@ -68,6 +68,7 @@
 #define I2C_DRIVERID_SAA7110	22	/* 				*/
 #define I2C_DRIVERID_MGATVO	23	/* Matrox TVOut			*/
 #define I2C_DRIVERID_SAA5249	24	/* SAA5249 and compatibles	*/
+#define I2C_DRIVERID_PCF8583	25	/* real time clock		*/
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
 #define I2C_DRIVERID_EXP1	0xF1
@@ -119,6 +120,7 @@
 #define I2C_HW_B_G400	0x09	/* Matrox G400				*/
 #define I2C_HW_B_I810	0x0a	/* Intel I810 				*/
 #define I2C_HW_B_RIVA	0x10	/* Riva based graphics cards		*/
+#define I2C_HW_B_IOC	0x11	/* IOC bit-wiggling			*/
 
 /* --- PCF 8584 based algorithms					*/
 #define I2C_HW_P_LP	0x00	/* Parallel port interface		*/
diff -u --recursive --new-file v2.3.44/linux/include/linux/kmod.h linux/include/linux/kmod.h
--- v2.3.44/linux/include/linux/kmod.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/kmod.h	Sun Feb 13 19:04:05 2000
@@ -3,6 +3,7 @@
 */
 
 #include <linux/config.h>
+#include <linux/errno.h>
 
 #ifdef CONFIG_KMOD
 extern int request_module(const char * name);
diff -u --recursive --new-file v2.3.44/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.44/linux/include/linux/mm.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/mm.h	Sun Feb 13 19:04:18 2000
@@ -436,7 +436,7 @@
 extern void remove_inode_page(struct page *);
 extern unsigned long page_unuse(struct page *);
 extern int shrink_mmap(int, int, zone_t *);
-extern void truncate_inode_pages(struct inode *, loff_t);
+extern void truncate_inode_pages(struct address_space *, loff_t);
 
 /* generic vm_area_ops exported for stackable file systems */
 extern int filemap_swapout(struct page * page, struct file *file);
diff -u --recursive --new-file v2.3.44/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.3.44/linux/include/linux/netdevice.h	Sat Feb 12 11:22:11 2000
+++ linux/include/linux/netdevice.h	Sun Feb 13 19:05:34 2000
@@ -427,7 +427,7 @@
 
 extern struct softnet_data softnet_data[NR_CPUS];
 
-#define HAS_NETIF_QUEUE
+#define HAVE_NETIF_QUEUE
 
 extern __inline__ void __netif_schedule(struct net_device *dev)
 {
diff -u --recursive --new-file v2.3.44/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.44/linux/kernel/fork.c	Tue Nov 23 22:42:21 1999
+++ linux/kernel/fork.c	Sun Feb 13 18:20:21 2000
@@ -252,18 +252,19 @@
 		tmp->vm_next = NULL;
 		file = tmp->vm_file;
 		if (file) {
+			struct inode *inode = file->f_dentry->d_inode;
 			get_file(file);
 			if (tmp->vm_flags & VM_DENYWRITE)
-				atomic_dec(&file->f_dentry->d_inode->i_writecount);
+				atomic_dec(&inode->i_writecount);
       
 			/* insert tmp into the share list, just after mpnt */
-			spin_lock(&file->f_dentry->d_inode->i_shared_lock);
+			spin_lock(&inode->i_mapping->i_shared_lock);
 			if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
 				mpnt->vm_next_share->vm_pprev_share =
 					&tmp->vm_next_share;
 			mpnt->vm_next_share = tmp;
 			tmp->vm_pprev_share = &mpnt->vm_next_share;
-			spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
+			spin_unlock(&inode->i_mapping->i_shared_lock);
 		}
 
 		/* Copy the pages, but defer checking for errors */
diff -u --recursive --new-file v2.3.44/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.44/linux/kernel/ksyms.c	Sat Feb 12 11:22:11 2000
+++ linux/kernel/ksyms.c	Sun Feb 13 10:15:25 2000
@@ -126,6 +126,7 @@
 #endif
 
 /* filesystem internal functions */
+EXPORT_SYMBOL(def_blk_fops);
 EXPORT_SYMBOL(in_group_p);
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
diff -u --recursive --new-file v2.3.44/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.3.44/linux/kernel/ptrace.c	Thu Nov 11 20:11:54 1999
+++ linux/kernel/ptrace.c	Sun Feb 13 10:31:07 2000
@@ -53,6 +53,7 @@
 		maddr = kmap(page);
 		memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
 		flush_page_to_ram(page);
+		flush_icache_page(vma, page);
 		kunmap(page);
 	} else {
 		maddr = kmap(page);
diff -u --recursive --new-file v2.3.44/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.44/linux/mm/filemap.c	Thu Feb 10 17:11:23 2000
+++ linux/mm/filemap.c	Sun Feb 13 18:20:21 2000
@@ -124,7 +124,7 @@
  * Truncate the page cache at a set offset, removing the pages
  * that are beyond that offset (and zeroing out partial pages).
  */
-void truncate_inode_pages(struct inode * inode, loff_t lstart)
+void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
 {
 	struct list_head *head, *curr;
 	struct page * page;
@@ -134,7 +134,7 @@
 	start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
 repeat:
-	head = &inode->i_mapping->pages;
+	head = &mapping->pages;
 	spin_lock(&pagecache_lock);
 	curr = head->next;
 	while (curr != head) {
diff -u --recursive --new-file v2.3.44/linux/mm/memory.c linux/mm/memory.c
--- v2.3.44/linux/mm/memory.c	Tue Jan 11 22:31:45 2000
+++ linux/mm/memory.c	Sun Feb 13 18:20:21 2000
@@ -860,16 +860,17 @@
 {
 	unsigned long partial, pgoff;
 	struct vm_area_struct * mpnt;
+	struct address_space *mapping = inode->i_mapping;
 
-	truncate_inode_pages(inode, offset);
-	spin_lock(&inode->i_shared_lock);
-	if (!inode->i_mmap)
+	truncate_inode_pages(mapping, offset);
+	spin_lock(&mapping->i_shared_lock);
+	if (!mapping->i_mmap)
 		goto out_unlock;
 
 	pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1);
 
-	mpnt = inode->i_mmap;
+	mpnt = mapping->i_mmap;
 	do {
 		struct mm_struct *mm = mpnt->vm_mm;
 		unsigned long start = mpnt->vm_start;
@@ -903,7 +904,9 @@
 		flush_tlb_range(mm, start, end);
 	} while ((mpnt = mpnt->vm_next_share) != NULL);
 out_unlock:
-	spin_unlock(&inode->i_shared_lock);
+	spin_unlock(&mapping->i_shared_lock);
+	if (inode->i_op && inode->i_op->truncate)
+		inode->i_op->truncate(inode);
 }
 
 
@@ -957,6 +960,7 @@
 			return -1;
 
 		flush_page_to_ram(page);
+		flush_icache_page(vma, page);
 	}
 
 	vma->vm_mm->rss++;
@@ -1057,6 +1061,7 @@
 	 * handle that later.
 	 */
 	flush_page_to_ram(new_page);
+	flush_icache_page(vma, new_page);
 	entry = mk_pte(new_page, vma->vm_page_prot);
 	if (write_access) {
 		entry = pte_mkwrite(pte_mkdirty(entry));
diff -u --recursive --new-file v2.3.44/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.44/linux/mm/mmap.c	Thu Feb 10 17:11:23 2000
+++ linux/mm/mmap.c	Sun Feb 13 18:20:21 2000
@@ -75,13 +75,14 @@
 	struct file * file = vma->vm_file;
 
 	if (file) {
+		struct inode *inode = file->f_dentry->d_inode;
 		if (vma->vm_flags & VM_DENYWRITE)
-			atomic_inc(&file->f_dentry->d_inode->i_writecount);
-		spin_lock(&file->f_dentry->d_inode->i_shared_lock);
+			atomic_inc(&inode->i_writecount);
+		spin_lock(&inode->i_mapping->i_shared_lock);
 		if(vma->vm_next_share)
 			vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
 		*vma->vm_pprev_share = vma->vm_next_share;
-		spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
+		spin_unlock(&inode->i_mapping->i_shared_lock);
 	}
 }
 
@@ -580,6 +581,7 @@
 {
 	unsigned long first = start & PGDIR_MASK;
 	unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK;
+	unsigned long start_index, end_index;
 
 	if (!prev) {
 		prev = mm->mmap;
@@ -607,12 +609,14 @@
 		break;
 	}
 no_mmaps:
-	first = first >> PGDIR_SHIFT;
-	last = last >> PGDIR_SHIFT;
-	if (last > first) {
-		clear_page_tables(mm, first, last-first);
-		flush_tlb_pgtables(mm, first << PGDIR_SHIFT, last << PGDIR_SHIFT);
-	}
+	/*
+	 * If the PGD bits are not consecutive in the virtual address, the
+	 * old method of shifting the VA >> by PGDIR_SHIFT doesn't work.
+	 */
+	start_index = pgd_index(first);
+	end_index = pgd_index(last);
+	if (end_index > start_index)
+		clear_page_tables(mm, start_index, end_index - start_index);
 }
 
 /* Munmap is split into 2 main parts -- this part which finds
@@ -884,16 +888,17 @@
 	file = vmp->vm_file;
 	if (file) {
 		struct inode * inode = file->f_dentry->d_inode;
+		struct address_space *mapping = inode->i_mapping;
 		if (vmp->vm_flags & VM_DENYWRITE)
 			atomic_dec(&inode->i_writecount);
       
 		/* insert vmp into inode's share list */
-		spin_lock(&inode->i_shared_lock);
-		if((vmp->vm_next_share = inode->i_mmap) != NULL)
-			inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
-		inode->i_mmap = vmp;
-		vmp->vm_pprev_share = &inode->i_mmap;
-		spin_unlock(&inode->i_shared_lock);
+		spin_lock(&mapping->i_shared_lock);
+		if((vmp->vm_next_share = mapping->i_mmap) != NULL)
+			mapping->i_mmap->vm_pprev_share = &vmp->vm_next_share;
+		mapping->i_mmap = vmp;
+		vmp->vm_pprev_share = &mapping->i_mmap;
+		spin_unlock(&mapping->i_shared_lock);
 	}
 }
 
diff -u --recursive --new-file v2.3.44/linux/net/core/dev.c linux/net/core/dev.c
--- v2.3.44/linux/net/core/dev.c	Thu Feb 10 17:11:24 2000
+++ linux/net/core/dev.c	Sun Feb 13 10:18:03 2000
@@ -911,15 +911,14 @@
 static void net_tx_action(struct softirq_action *h)
 {
 	int cpu = smp_processor_id();
-	unsigned long flags;
 
 	if (softnet_data[cpu].completion_queue) {
 		struct sk_buff *clist;
 
-		local_irq_save(flags);
+		local_irq_disable();
 		clist = softnet_data[cpu].completion_queue;
 		softnet_data[cpu].completion_queue = NULL;
-		local_irq_restore(flags);
+		local_irq_enable();
 
 		while (clist != NULL) {
 			struct sk_buff *skb = clist;
@@ -933,10 +932,10 @@
 	if (softnet_data[cpu].output_queue) {
 		struct net_device *head;
 
-		local_irq_save(flags);
+		local_irq_disable();
 		head = softnet_data[cpu].output_queue;
 		softnet_data[cpu].output_queue = NULL;
-		local_irq_restore(flags);
+		local_irq_enable();
 
 		while (head != NULL) {
 			struct net_device *dev = head;
diff -u --recursive --new-file v2.3.44/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.3.44/linux/net/ipv6/af_inet6.c	Thu Feb 10 17:11:24 2000
+++ linux/net/ipv6/af_inet6.c	Sun Feb 13 10:18:03 2000
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.53 2000/02/04 21:04:08 davem Exp $
+ *	$Id: af_inet6.c,v 1.54 2000/02/12 23:34:45 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -451,7 +451,7 @@
 	inet6_bind,
 	inet_dgram_connect,		/* ok		*/
 	sock_no_socketpair,		/* a do nothing	*/
-	inet_accept,			/* ok		*/
+	sock_no_accept,			/* a do nothing	*/
 	inet6_getname, 
 	datagram_poll,			/* ok		*/
 	inet6_ioctl,			/* must change  */
diff -u --recursive --new-file v2.3.44/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.3.44/linux/net/irda/irda_device.c	Tue Feb  1 01:35:44 2000
+++ linux/net/irda/irda_device.c	Sun Feb 13 18:20:21 2000
@@ -426,12 +426,8 @@
 	memset(dev->broadcast, 0xff, 4);
 
 	dev->mtu = 2048;
-	dev->tbusy = 1;
-	
 	dev_init_buffers(dev);
-
 	dev->flags = IFF_NOARP;
-	
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.44/linux/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c
--- v2.3.44/linux/net/irda/irlan/irlan_client.c	Wed Dec 29 13:13:21 1999
+++ linux/net/irda/irlan/irlan_client.c	Sun Feb 13 18:20:21 2000
@@ -126,7 +126,7 @@
 	 * is up, that means that the "user" really wants to connect. If not
 	 * we notify the user about the possibility of an IrLAN connection
 	 */
-	if (self->dev.start) {
+	if (test_bit(LINK_STATE_START, &self->dev.state)) {
 		/* Open TSAPs */
 		irlan_client_open_ctrl_tsap(self);
  		irlan_open_data_tsap(self);
diff -u --recursive --new-file v2.3.44/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.3.44/linux/net/irda/irlan/irlan_common.c	Fri Jan  7 19:13:23 2000
+++ linux/net/irda/irlan/irlan_common.c	Sun Feb 13 18:20:21 2000
@@ -120,7 +120,7 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if device still configured */
-	if (self->dev.start) {
+	if (test_bit(LINK_STATE_START, &self->dev.state)) {
 		IRDA_DEBUG(0, __FUNCTION__ 
 		      "(), notifying irmanager to stop irlan!\n");
 		mgr_event.event = EVENT_IRLAN_STOP;
@@ -363,7 +363,7 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if device is still configured */
-	if (self->dev.start) {
+	if (test_bit(LINK_STATE_START, &self->dev.state)) {
 		IRDA_DEBUG(0, __FUNCTION__ 
 		       "(), Device still configured, closing later!\n");
 
@@ -420,7 +420,7 @@
 		irlan_open_unicast_addr(self);
 	}
 	/* Ready to transfer Ethernet frames (at last) */
-	self->dev.tbusy = 0;
+	netif_start_queue(&self->dev);
 }
 
 void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
@@ -454,8 +454,7 @@
  	irlan_set_multicast_filter(self, TRUE);
 
 	/* Ready to transfer Ethernet frames */
-	self->dev.tbusy = 0;
-
+	netif_start_queue(&self->dev);
 	irlan_eth_send_gratuitous_arp(&self->dev);
 }
 
@@ -1196,7 +1195,7 @@
 						  buf+len);
 			
 			len += sprintf(buf+len, "tx busy: %s\n", 
-				       self->dev.tbusy ? "TRUE" : "FALSE");
+				       test_bit(LINK_STATE_XOFF, &self->dev.state) ? "TRUE" : "FALSE");
 			
 			len += sprintf(buf+len, "\n");
 		}
diff -u --recursive --new-file v2.3.44/linux/net/irda/irlan/irlan_eth.c linux/net/irda/irlan/irlan_eth.c
--- v2.3.44/linux/net/irda/irlan/irlan_eth.c	Fri Jan  7 19:13:23 2000
+++ linux/net/irda/irlan/irlan_eth.c	Sun Feb 13 18:20:21 2000
@@ -62,8 +62,6 @@
 	dev->get_stats	        = irlan_eth_get_stats;
 	dev->set_multicast_list = irlan_eth_set_multicast_list;
 
-	dev->tbusy = 1;
-	
 	ether_setup(dev);
 	
 	/* 
@@ -124,9 +122,7 @@
 	ASSERT(self != NULL, return -1;);
 
 	/* Ready to play! */
-/* 	dev->tbusy = 0; */ /* Wait until data link is ready */
-	dev->interrupt = 0;
-	dev->start = 1;
+/* 	netif_start_queue(dev) */ /* Wait until data link is ready */
 
 	self->notify_irmanager = TRUE;
 
@@ -153,9 +149,8 @@
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 	
 	/* Stop device */
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
+	
 	irlan_mod_dec_use_count();
 
 	irlan_close_data_channel(self);
@@ -192,10 +187,6 @@
 	ASSERT(self != NULL, return 0;);
 	ASSERT(self->magic == IRLAN_MAGIC, return 0;);
 
-	/* Check if IrTTP can accept more frames */
-	if (dev->tbusy)
-		return -EBUSY;
-	
 	/* skb headroom large enough to contain all IrDA-headers? */
 	if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
 		struct sk_buff *new_skb = 
@@ -279,7 +270,7 @@
  * Function irlan_eth_flow (status)
  *
  *    Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by 
- *    controlling the dev->tbusy variable.
+ *    controlling the queue stop/start.
  */
 void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
 {
@@ -297,15 +288,13 @@
 	
 	switch (flow) {
 	case FLOW_STOP:
-		dev->tbusy = 1;
+		netif_stop_queue(dev);
 		break;
 	case FLOW_START:
 	default:
 		/* Tell upper layers that its time to transmit frames again */
-		dev->tbusy = 0;
-
 		/* Schedule network layer */
-		mark_bh(NET_BH);		
+		netif_start_queue(dev);
 		break;
 	}
 }
diff -u --recursive --new-file v2.3.44/linux/net/khttpd/sockets.c linux/net/khttpd/sockets.c
--- v2.3.44/linux/net/khttpd/sockets.c	Fri Jan 28 15:09:09 2000
+++ linux/net/khttpd/sockets.c	Sun Feb 13 10:42:03 2000
@@ -71,8 +71,6 @@
 
 	/* Grrr... setsockopt() does this. */
 	sock->sk->reuse   = 1;
-	/* Wow!!! */
-	sock->sk->linger  = 1;
 
 	/* Now, start listening on the socket */
 	
diff -u --recursive --new-file v2.3.44/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.3.44/linux/net/netrom/nr_dev.c	Wed Aug 18 11:38:49 1999
+++ linux/net/netrom/nr_dev.c	Sun Feb 13 18:20:21 2000
@@ -62,7 +62,7 @@
 {
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
-	if (!dev->start) {
+	if (!test_bit(LINK_STATE_START, &dev->state)) {
 		stats->rx_errors++;
 		return 0;
 	}
@@ -181,60 +181,25 @@
 
 static int nr_open(struct net_device *dev)
 {
-	dev->tbusy = 0;
-	dev->start = 1;
-
 	MOD_INC_USE_COUNT;
-
+	netif_start_queue(dev);
 	ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
-
 	return 0;
 }
 
 static int nr_close(struct net_device *dev)
 {
-	dev->tbusy = 1;
-	dev->start = 0;
-
+	netif_stop_queue(dev);
 	ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
-
 	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
 static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
-
-	if (skb == NULL || dev == NULL)
-		return 0;
-
-	if (!dev->start) {
-		printk(KERN_ERR "NET/ROM: nr_xmit - called when iface is down\n");
-		return 1;
-	}
-
-	cli();
-
-	if (dev->tbusy != 0) {
-		sti();
-		stats->tx_errors++;
-		return 1;
-	}
-
-	dev->tbusy = 1;
-
-	sti();
-
-	kfree_skb(skb);
-
+	dev_kfree_skb(skb);
 	stats->tx_errors++;
-
-	dev->tbusy = 0;
-
-	mark_bh(NET_BH);
-
 	return 0;
 }
 
@@ -246,7 +211,6 @@
 int nr_init(struct net_device *dev)
 {
 	dev->mtu		= NR_MAX_PACKET_SIZE;
-	dev->tbusy		= 0;
 	dev->hard_start_xmit	= nr_xmit;
 	dev->open		= nr_open;
 	dev->stop		= nr_close;
diff -u --recursive --new-file v2.3.44/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.44/linux/net/netsyms.c	Thu Feb 10 17:11:25 2000
+++ linux/net/netsyms.c	Sun Feb 13 10:15:25 2000
@@ -540,6 +540,7 @@
 #ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);
+EXPORT_SYMBOL(sysctl_ip_default_ttl);
 #endif
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
diff -u --recursive --new-file v2.3.44/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.3.44/linux/net/rose/rose_dev.c	Wed Aug 18 11:38:49 1999
+++ linux/net/rose/rose_dev.c	Sun Feb 13 18:20:21 2000
@@ -57,7 +57,7 @@
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 #ifdef CONFIG_INET
-	if (!dev->start) {
+	if (!test_bit(LINK_STATE_START, &dev->state)) {
 		stats->rx_errors++;
 		return 0;
 	}
@@ -145,25 +145,17 @@
 
 static int rose_open(struct net_device *dev)
 {
-	dev->tbusy = 0;
-	dev->start = 1;
-
 	MOD_INC_USE_COUNT;
-
+	netif_start_queue(dev);
 	rose_add_loopback_node((rose_address *)dev->dev_addr);
-
 	return 0;
 }
 
 static int rose_close(struct net_device *dev)
 {
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	MOD_DEC_USE_COUNT;
-
+	netif_stop_queue(dev);
 	rose_del_loopback_node((rose_address *)dev->dev_addr);
-
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -171,34 +163,12 @@
 {
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
-	if (skb == NULL || dev == NULL)
-		return 0;
-
-	if (!dev->start) {
+	if (!test_bit(LINK_STATE_START, &dev->state)) {
 		printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n");
 		return 1;
 	}
-
-	cli();
-
-	if (dev->tbusy != 0) {
-		sti();
-		stats->tx_errors++;
-		return 1;
-	}
-
-	dev->tbusy = 1;
-
-	sti();
-
-	kfree_skb(skb);
-
+	dev_kfree_skb(skb);
 	stats->tx_errors++;
-
-	dev->tbusy = 0;
-
-	mark_bh(NET_BH);
-
 	return 0;
 }
 
@@ -210,7 +180,6 @@
 int rose_init(struct net_device *dev)
 {
 	dev->mtu		= ROSE_MAX_PACKET_SIZE - 2;
-	dev->tbusy		= 0;
 	dev->hard_start_xmit	= rose_xmit;
 	dev->open		= rose_open;
 	dev->stop		= rose_close;
diff -u --recursive --new-file v2.3.44/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.3.44/linux/net/wanrouter/wanmain.c	Fri Jan 28 15:09:09 2000
+++ linux/net/wanrouter/wanmain.c	Sun Feb 13 18:20:21 2000
@@ -526,7 +526,10 @@
 	for (dev = wandev->dev; dev;)
 	{
 		if (delete_interface(wandev, dev->name, 0))
-			dev = dev->slave;
+		{
+			struct net_device **slave = dev->priv;
+			dev = *slave;
+		}
 	}
 	if (wandev->ndev)
 		return -EBUSY;	/* there are opened interfaces  */
@@ -608,8 +611,10 @@
 #endif				
 			err = register_netdev(dev);
 			if (!err) {
+				struct net_device **slave = dev->priv;
+
 				cli();	/***** critical section start *****/
-				dev->slave = wandev->dev;
+				*slave = wandev->dev;
 				wandev->dev = dev;
 				++wandev->ndev;
 				sti();	/****** critical section end ******/
@@ -684,14 +689,19 @@
 {
 	struct net_device *dev, *prev;
 
-	for (dev = wandev->dev, prev = NULL;
-		dev && strcmp(name, dev->name);
-		prev = dev, dev = dev->slave);
+	dev = wandev->dev;
+	prev = NULL;
+	while (dev && strcmp(name, dev->name)) {
+		struct net_device **slave = dev->priv;
+
+		prev = dev;
+		dev = *slave;
+	}
 
 	if (dev == NULL)
 		return -ENODEV;	/* interface not found */
 
-	if (dev->start) {
+	if (test_bit(LINK_STATE_START, &dev->state)) {
 		if (force) {
 			printk(KERN_WARNING
 				"%s: deleting opened interface %s!\n",
@@ -705,10 +715,16 @@
 		wandev->del_if(wandev, dev);
 
 	cli();			/***** critical section start *****/
-	if (prev)
-		prev->slave = dev->slave;
-	else
-		wandev->dev = dev->slave;
+	if (prev) {
+		struct net_device **prev_slave = prev->priv;
+		struct net_device **slave = dev->priv;
+
+		*prev_slave = *slave;
+	} else {
+		struct net_device **slave = dev->priv;
+
+		wandev->dev = *slave;
+	}
 	--wandev->ndev;
 	sti();			/****** critical section end ******/
 
diff -u --recursive --new-file v2.3.44/linux/scripts/tkcond.c linux/scripts/tkcond.c
--- v2.3.44/linux/scripts/tkcond.c	Mon Oct  4 15:49:30 1999
+++ linux/scripts/tkcond.c	Sun Feb 13 10:45:13 2000
@@ -498,6 +498,7 @@
 	    case token_define_int:
 	    case token_define_string:
 	    case token_define_tristate:
+	    case token_endmenu:
 	    case token_hex:
 	    case token_int:
 	    case token_mainmenu_option:
